Spring 5.x 源码之旅二十getBean详解六
Spring 5.x 源码之旅二十getBean详解六
创建参数持有器
我就用两个工厂方法来做例子,其实他们差异是一样的,会报错,没关系,我们主要分析过程原理:
首先会用参数名字探测器去获取参数的名字,其实内部是用ASM
读取字节码来操作的,主要是LocalVariableTableParameterNameDiscoverer
这个类,二进制流读取class
文件,然后分析,比较复杂,有兴趣的可以去看。我们直接就核心方法分析吧。
createArgumentArray
留下了一般的情况,不包括用xml
方式设置参数值或者手动设置了ConstructorArgumentValues
,就是最普通的形式。根据参数的数量,开始遍历参数,这里就会涉及参数的索引paramIndex
啦,xml
里会用到,首先将工厂方法(构造方法)和索引封装成一个通用的MethodParameter
类型处理,然后进行自动装配,解析出参数对象,里面很复杂,一会儿说,最后要注册依赖和被依赖的bean
,其实就是做缓存,下次可以直接用。
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
//类型转换器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);//参数持有器
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);//构造器参数值集合
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);//装配的bean名字
//带参数的话
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
String paramName = (paramNames != null ? paramNames[paramIndex] : "");//获取参数名字
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
...
}
if (valueHolder != null) {
...
}
else {
//获取统一的方法参数类型
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
if (!autowiring) {
throw new UnsatisfiedDependencyException(
...
}
try {//解析自动装配参数,找到会进行实例化
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
//注册依赖的bean
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
MethodParameter的forExecutable封装方法参数
这里就是将工厂方法和构造方法一起处理成通用形式,方便后面统一处理。
public static MethodParameter forExecutable(Executable executable, int parameterIndex) {
if (executable instanceof Method) {
return new MethodParameter((Method) executable, parameterIndex);
}
else if (executable instanceof Constructor) {
return new MethodParameter((Constructor<?>) executable, parameterIndex);
}
else {
throw new IllegalArgumentException("Not a Method/Constructor: " + executable);
}
}
MethodParameter的构造方法
其实就是把方法和索引设置进去,还有一个嵌套层,比如list
里嵌套list
这种,暂时不用管,我们还是按一般的来,嵌套就是层就是1
,如果不是1
,后面会去查找内部的嵌套类型。
public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
Assert.notNull(method, "Method must not be null");
this.executable = method;
this.parameterIndex = validateIndex(method, parameterIndex);
this.nestingLevel = nestingLevel;
}
resolveAutowiredArgument解析自动装配参数
首先判断是否是注入点类型InjectionPoint
,这个类型就是描述一个方法或者构造器的参数或者一个属性,因为这些都是可以自动注入的地方。如果是的话,就直接获取注入点返回,否则就让beanFactory
来解析依赖,在这之前,先把MethodParameter
封装成DependencyDescriptor
,也就是注入点。
protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
Class<?> paramType = param.getParameterType();
if (InjectionPoint.class.isAssignableFrom(paramType)) {//是否是注入点类型,比如DependencyDescriptor
InjectionPoint injectionPoint = currentInjectionPoint.get();
if (injectionPoint == null) {
throw new IllegalStateException("No current InjectionPoint available for " + param);
}
return injectionPoint;
}
try {//beanFactory解析依赖
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
catch (NoUniqueBeanDefinitionException ex) {
throw ex;
}
catch (NoSuchBeanDefinitionException ex) {
if (fallback) {
...
}
throw ex;
}
}
DefaultListableBeanFactory的resolveDependency
判断依赖是什么类型,根据不同类型来处理,当然我们肯定是最后的那种情况,我们自定义的类型,看看是否是懒加载的,如果不是就立即调用doResolveDependency
来解析。
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//设置参数名字探索器
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {//Optional类型
return createOptionalDependency(descriptor, requestingBeanName);
}//是对象工厂类型或者对象提供者类型
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}//java扩展的注入类
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {//我们自己只能的类型,先看是否是懒加载,是的话就直接返回,否则要去解析依赖
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
MethodParameter的getDependencyType获取依赖类型
这里如果有属性存在,而且嵌套类型大于1
,就会找出真实类型,比如List<String>
这种,String
的嵌套就是2
,真实类型就是String。当然我们不是属性注入,所以直接调用MethodParameter
的getNestedParameterType
。
public Class<?> getDependencyType() {
if (this.field != null) {
if (this.nestingLevel > 1) {
Type type = this.field.getGenericType();
for (int i = 2; i <= this.nestingLevel; i++) {
if (type instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
type = args[args.length - 1];
}
}
if (type instanceof Class) {
return (Class<?>) type;
}
else if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getRawType();
if (arg instanceof Class) {
return (Class<?>) arg;
}
}
return Object.class;
}
else {
return this.field.getType();
}
}
else {
return obtainMethodParameter().getNestedParameterType();
}
}
MethodParameter的getNestedParameterType
发现了大量重复代码,其实大部分是跟属性的处理逻辑一样的,如果只有1层,就直接调用getParameterType
。
public Class<?> getNestedParameterType() {
if (this.nestingLevel > 1) {
Type type = getGenericParameterType();
for (int i = 2; i <= this.nestingLevel; i++) {
if (type instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
Integer index = getTypeIndexForLevel(i);
type = args[index != null ? index : args.length - 1];
}
// TODO: Object.class if unresolvable
}
if (type instanceof Class) {
return (Class<?>) type;
}
else if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getRawType();
if (arg instanceof Class) {
return (Class<?>) arg;
}
}
return Object.class;
}
else {
return getParameterType();
}
}
DependencyDescriptor的getNestedParameterType
存在类型就直接返回了,否则就要进行其他处理获得参数类型。
public Class<?> getParameterType() {
Class<?> paramType = this.parameterType;
if (paramType != null) {
return paramType;
}
if (getContainingClass() != getDeclaringClass()) {
paramType = ResolvableType.forMethodParameter(this, null, 1).resolve();
}
if (paramType == null) {
paramType = computeParameterType();
}
this.parameterType = paramType;
return paramType;
}
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。
上一篇: 正确地使用加密与认证技术
下一篇: 数据库存储层次、树形结构的标准做法