Spring源码剖析之推断构造方法

思路分析

Spring中的一个bean,需要实例化得到一个对象,而实例化就需要用到构造方法。 一般情况下,一个类只有一个构造方法:要么是无参的构造方法,要么是有参的构造方法。

如果只有一个无参的构造方法,那么实例化就只能使用这个构造方法了。如果只有一个有参的构造方法,那么实例化时能使用这个构造方法吗?

要分情况讨论:

        1.使用AnnotationConfigApplicationContext,会使用这个构造方法进行实例化,那么Spring会根据构造方法的参数信息去寻找bean,然后传给构造方法

        2.使用ClassPathXmlApplicationContext,表示使用XML的方式来使用bean,要么在XML中指定构造方法的参数值(手动指定),要么配置autowire=constructor让Spring自动去寻找bean做为构造方法参数值。

上面是只有一个构造方法的情况,那么如果有多个构造方法呢? 又分为两种情况,多个构造方法中存不存在无参的构造方法。

分析:一个类存在多个构造方法,那么Spring进行实例化之前,该如何去确定到底用哪个构造方法呢?

  1. 如果开发者指定了想要使用的构造方法,那么就用这个构造方法
  2. 如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法
  3. 如果开发者也没有让Spring自动去选择构造方法,则Spring利用无参构造方法,如果没有无参构造方法,则报错

针对第一点,开发者可以通过什么方式来指定使用哪个构造方法呢?

1. xml中的<constructor-arg>标签,这个标签表示构造方法参数,所以可以根据这个确定想要使用的构造方法的参数个数,从而确定想要使用的构造方法

<bean id="orderService" class="com.spring.OrderService"/>
<bean id="productService" class="com.spring.ProductService"/>

<bean id="userService" class="com.spring.UserService">
   <constructor-arg index="0" ref="orderService"/>
   <constructor-arg index="1" ref="productService"/>
</bean>

2. 通过@Autowired注解,@Autowired注解可以写在构造方法上,所以哪个构造方法上写了@Autowired注解,表示开发者想使用哪个构造方法,当然,它和第一个方式的不同点是,通过xml的方式,我们直接指定了构造方法的参数值,而通过@Autowired注解的方式,需要Spring通过byType+byName的方式去找到符合条件的bean作为构造方法的参数值

@Component
public class UserService {

    private OrderService orderService;
    private ProductService productService;

    public UserService() {
        System.out.println(0);
    }

    @Autowired
    public UserService(OrderService orderService, ProductService productService) {
        System.out.println(2);    
        this.orderService = orderService;
        this.productService = productService;
    }
}

再来看第二点,如果开发者没有指定想要使用的构造方法,则看开发者有没有让Spring自动去选择构造方法,对于这一点,只能用在ClassPathXmlApplicationContext,因为通过AnnotationConfigApplicationContext 没有办法去指定某个bean可以自动去选择构造方法,而通过ClassPathXmlApplicationContext 可以在xml中指定某个bean的autowire为constructor,虽然这个属性表示通过构造方法自动注入,所以需要自动的去选择一个构造方法进行自动注入,因为是构造方法,所以顺便是进行实例化。 

<bean id="userService" class="com.spring.UserService" autowire="constructor"/>

当然,还有一种情况,就是多个构造方法上写了@Autowired注解,那么此时Spring会报错。

但是,因为@Autowired还有一个属性required,默认为ture,所以一个类中,只有能一个构造方法标注了@Autowired或@Autowired(required=true),有多个会报错。但是可以有多个@Autowired(required=false),这种情况下,需要Spring从这些构造方法中去自动选择一个构造方法。

思路总结

1、 默认情况,用无参构造方法,或者只有一个构造方法就用那一个。

2、 程序员指定了构造方法入参值,通过getBean()或者BeanDefinition.getConstructorArgumentValues()指定,那就用所匹配的构造方法。

3、 程序员想让Spring自动选择构造方法以及构造方法的入参值, autowire = "constructor"。

4、 程序员通过@Autowired注解指定了某个构造方法,但是希望Spring自动找该构造方法的入参值。

源码剖析  

createBeanInstance

AbstractAutowireCapableBeanFactory类中的createBeanInstance()方法会去创建一个Bean实例,其中Object[] args 就是调用getObject()方法传入的args参数。

    // 创建Bean实例
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // 拿到Bean的Class对象
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
        // 不是public的且不可访问 则抛异常
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException();
        }
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName, mbd);
        }
        // @Bean对应的BeanDefinition
        // 创建@Bean定义的Bean对象
        if (mbd.getFactoryMethodName() != null) {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
        // 一个原型的BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来
        // 避免每次都要进行构造方法推断
        boolean resolved = false;			 // 标识是否已经解析出要执行的构造方法	
        boolean autowireNecessary = false;   // 标识是否需要对构造方法的参数进行依赖注入

        // 没有明确指定构造方法参数
        // 在getBean()方法时指定了args时 不考虑缓存
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                // resolvedConstructorOrFactoryMethod 是缓存的构造方法Constructor对象
                // 有缓存构造方法或工厂方法
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    resolved = true;
                    // 表示有没有必要进行注入,比如当前BeanDefinition用的无参构造,那么autowireNecessary = false
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
        // 构造方法已经确定
        if (resolved) {
            // 需要对构造方法参数进行依赖注入(构造方法注入)
            if (autowireNecessary) {
                // 方法内会拿到缓存好的构造方法入参
                return autowireConstructor(beanName, mbd, null, null);

            // 不需要对构造方法参数进行依赖注入	
            } else {
                // 表示用的是默认的无参构造方法,直接进行实例化 
                return instantiateBean(beanName, mbd);
            }
        }
        // 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中哪个构造方法
        // 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
        // ctors = null有两种情况:1.只有一个无参构造;2.有多个构造方法

        // 条件1:ctors != null,说明有加了@Autowired的  构造方法
        // 条件2:bean的自动注入模式是 AUTOWIRE_CONSTRUCTOR
        // 条件3:BeanDefinition中添加了构造方法的参数和值
        // 条件4:调用getBean()方法时传入了args参数
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
            // 构造方法注入		
            return autowireConstructor(beanName, mbd, ctors, args);
        }
        // 以上情况都不匹配,则使用无参构造方法
        // 若没有无参构造,则报错
        return instantiateBean(beanName, mbd);
    }

createBeanInstance主要过程: 

  1. 根据BeanDefinition加载类得到Class对象;
  2. 如果BeanDefinition绑定了一个Supplier,那就调用Supplier的get方法得到一个对象并直接返回;
  3. 如果BeanDefinition中存在factoryMethodName,也就是通过@Bean定义的bean对象,那么就调用该工厂方法得到一个bean对象并返回;
  4. 如果BeanDefinition已经自动构造过了,那就调用autowireConstructor()自动构造一个对象
  5. 调用SmartInstantiationAwareBeanPostProcessordetermineCandidateConstructors()方法得到哪些构造方法是可以用的;
  6. 如果存在可用得构造方法,或者当前BeanDefinition的autowired是AUTOWIRE_CONSTRUCTOR,或者BeanDefinition中指定了构造方法参数值,或者创建Bean的时候指定了构造方法参数值,那么就调用autowireConstructor()方法自动构造一个对象;
  7. 最后,如果不是上述情况,就根据无参的构造方法实例化一个对象。 

determineCandidateConstructors

// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中哪个构造方法
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
		throws BeansException {
	if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
		for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
			Constructor<?>[] ctors = bp.determineCandidateConstructors(beanClass, beanName);
			if (ctors != null) {
				return ctors;
			}
		}
	}
	return null;
}

AutowiredAnnotationBeanPostProcessor 实现了SmartInstantiationAwareBeanPostProcessor的 determineCandidateConstructors()方法,会把加了@Autowired注解的构造方法找出来。

    // 推断候选者构造方法
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {
        checkLookupMethods(beanClass, beanName);

        // Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
        // 先从缓存中找
        Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        // 缓存中没有
        if (candidateConstructors == null) {
            // 加锁
            synchronized (this.candidateConstructorsCache) {
                // 再次从缓存中找  DCL
                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                // 缓存中还是没有
                if (candidateConstructors == null) {
                    Constructor<?>[] rawCandidates;
                    // 拿到本类中所有的构造方法,包括public、protected、default、privite的
                    // 如果beanClass表示接口、基元类型、数组或 void,则返回长度为0的数组。
                    rawCandidates = beanClass.getDeclaredConstructors();

                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    // 记录required为true的构造方法,一个类中只能有一个required为true的构造方法
                    Constructor<?> requiredConstructor = null;
                    // 记录默认的无参构造方法
                    Constructor<?> defaultConstructor = null;

                    // 遍历所有的构造方法
                    for (Constructor<?> candidate : rawCandidates) {
                        // 当前构造方法是否有@Autowired注解
                        MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
                        // ann == null,说明当前构造方法上没有@Autowired注解
                        if (ann == null) {
                            // 如果当前是代理类,则得到被代理类的类型
                            Class<?> userClass = ClassUtils.getUserClass(beanClass);
                            // userClass != beanClass,说明当前类是代理类
                            if (userClass != beanClass) {
                                // 被代理类的构造方法上是否有@Autowired注解
                                Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                ann = findAutowiredAnnotation(superCtor);
                            }
                        }
                        // 当前构造方法上有@Autowired注解
                        if (ann != null) {
                            // 整个类中如果已经有了一个required为true的构造方法,那就不能再有其他加了@Autowired的构造方法
                            if (requiredConstructor != null) {
                                throw new BeanCreationException();
                            }
                            // @Autowired的required属性值
                            boolean required = determineRequiredStatus(ann);
                            // 如果required = true
                            if (required) {
                                // 如果还有其他构造方法有@Autowired则报错
                                if (!candidates.isEmpty()) {
                                    throw new BeanCreationException();
                                }
                                // 当前构造方法为required为true的构造方法
                                requiredConstructor = candidate;
                            }
                            // 记录所有加了@Autowired的构造方法,不管是required是true还是false
                            // 如果默认无参的构造方法上也加了@Autowired,也会加入到candidates中
                            candidates.add(candidate);

                        // 当前构造方法上没有@Autowired注解且是无参构造方法
                        // 那么该构造方法就是默认的无参构造方法
                        } else if (candidate.getParameterCount() == 0) {
                            defaultConstructor = candidate;
                        }

                        // 有可能存在有参、并且没有添加@Autowired的构造方法
                    }
                    // 有加了@Autowired的构造方法
                    // 要么有多个required = false构造方法,要么只有一个required = true的构造方法
                    if (!candidates.isEmpty()) {
                        // 没有required = true的构造方法,则都是required = false构造方法
                        if (requiredConstructor == null) {
                            // 如果有无参构造方法,则将无参构造方法加入到候选者集合
                            if (defaultConstructor != null) {
                                candidates.add(defaultConstructor);
                            }
                        }
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    // 没有加了@Autowired的构造方法
                    // 只有一个有参构造方法
                    } else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                        candidateConstructors = new Constructor<?>[]{rawCandidates[0]};
                    } else {
                        // 没有加了@Autowired的构造方法,且有多个有参构造或一个无参构造,则返回空
                        candidateConstructors = new Constructor<?>[0];
                    }
                    // 将推断出来的候选者构造方法放入缓存
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }
        return (candidateConstructors.length > 0 ? candidateConstructors : null);
    }

AutowiredAnnotationBeanPostProcessor 推断构造方法的主要过程:

主要分两种情况

  • 不存在加了@Autowired的构造方法:
    • 若只有一个有参构造方法,则返回此构造方法;
    • 若有多个构造方法,返回null;
    • 若只有一个无参构造方法,返回null。
  • 存在加了@Autowired的构造方法:
    •  若只有一个required = true的构造方法,则返回此构造方法;
    •  若有多个required = true的构造方法,则抛异常;
    •  若有一个required = true的构造方法和其他required = false的构造方法,则抛异常;
    •  没有required = true的构造方法,则返回required = false的构造方法以及无参构造方法 。

autowireConstructor

    // 从chosenCtors中选择要使用的构造方法
    // explicitArgs: getBean()方法传入的args
    public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);

        Constructor<?> constructorToUse = null;  // 记录选中构造方法
        ArgumentsHolder argsHolderToUse = null;  // 记录构造方法参数
        Object[] argsToUse = null;
        //如果getBean()传入了args,则构造方法要使用的入参就已经确定好了
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        } else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                // 拿到指定或缓存的构造方法
                constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
                if (constructorToUse != null && mbd.constructorArgumentsResolved) {
                    // 缓存的构造方法参数
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        // beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference("orderService"));
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            if (argsToResolve != null) {
                // beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference("orderService"));
                // 解析RuntimeBeanReference,到容器中查找名称为orderService的Bean对象
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
            }
        }
        // 没有确定要使用的构造方法,或者确定了构造方法但是方法入参没有确定
        if (constructorToUse == null || argsToUse == null) {
            // 传入的候选构造方法
            Constructor<?>[] candidates = chosenCtors;
            // 没有传入候选的构造方法,则拿到类中所有的构造方法
            if (candidates == null) {
                Class<?> beanClass = mbd.getBeanClass();
                candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors());
            }
            // 如果只有一个候选构造方法,并且没有指定要使用构造方法参数值,并且该构造方法是无参的,
            // 也就是只有一个无参构造,那就直接用这个无参构造方法进行实例化了
            if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
                Constructor<?> uniqueCandidate = candidates[0];
                if (uniqueCandidate.getParameterCount() == 0) {
                    // 缓存构造方法和构造参数
                    synchronized (mbd.constructorArgumentLock) {
                        mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                        mbd.constructorArgumentsResolved = true;
                        mbd.resolvedConstructorArguments = EMPTY_ARGS;
                    }
                    // 根据构造方法uniqueCandidate、构造参数 实例化对象
                    bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
                    return bw;
                }
            }
            // 是否需要对构造方法参数进行依赖注入
            boolean autowiring = (chosenCtors != null ||
                    mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
            ConstructorArgumentValues resolvedValues = null;

            // 确定要选择的构造方法参数个数的最小值,后续判断候选构造方法的参数如果小于minNrOfArgs,则直接pass掉
            int minNrOfArgs;
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            } else {
                // 如果通过BeanDefinition传入了构造方法参数值,因为有可能通过下标指定了
                // 比如0位置有值,2位置有值,虽然只指定了两个值,但是构造方法需要的参数个数最小值是3
                ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                resolvedValues = new ConstructorArgumentValues();
                // 处理RuntimeBeanReference
                minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
            }
            // 对候选构造方法进行排序,public的方法排在最前面,都是public的情况下参数个数越多越靠前
            AutowireUtils.sortConstructors(candidates);
            int minTypeDiffWeight = Integer.MAX_VALUE;
            // 参数个数相同且得分也相同的构造方法
            Set<Constructor<?>> ambiguousConstructors = null;
            // 记录通过参数找不到对应的Bean而抛出的异常
            Deque<UnsatisfiedDependencyException> causes = null;
            // 遍历每个构造方法,进行筛选
            for (Constructor<?> candidate : candidates) {
                // 构造方法参数个数
                int parameterCount = candidate.getParameterCount();
                // 本次遍历时,以前已经选出来的所要用的构造方法和入参对象,并且入参对象个数比当前这个构造方法的参数个数多,则不用再遍历了
                if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
                    break;
                }
                // 参数个数小于所要求的参数个数,则不会考虑该构造方法
                if (parameterCount < minNrOfArgs) {
                    continue;
                }
                ArgumentsHolder argsHolder;
                // 构造方法参数类型
                Class<?>[] paramTypes = candidate.getParameterTypes();
                // 没有通过getBean()所指定构成方法参数值
                if (resolvedValues != null) {
                    try {
                        String[] paramNames = null;
                        if (resolvedValues.containsNamedArgument()) {
                            // 如果在构造方法上使用了@ConstructorProperties,那么就直接取定义的值作为构造方法的参数名
                            paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
                            if (paramNames == null) {
                                // 获取参数名解析器
                                // StandardReflectionParameterNameDiscoverer: 通过反射(1.8)获取方法参数名称
                                // LocalVariableTableParameterNameDiscoverer: 解析字节码本地变量表获得方法参数名称
                                ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                                if (pnd != null) {
                                    // 解析方法参数名
                                    paramNames = pnd.getParameterNames(candidate);
                                }
                            }
                        }
                        // 根据参数类型和参数名,找到对应的Bean对象
                        argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
                                getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
                    } catch (UnsatisfiedDependencyException ex) {
                        // 如果通过参数找不到对应的Bean而抛异常,则先记录异常
                        if (causes == null) {
                            causes = new ArrayDeque<>(1);
                        }
                        causes.add(ex);
                        continue;
                    }
                } else {
                    // 没有通过BeanDefinition的指定构造方法参数值,但是在调用getBean方法时传入了参数值,那就表示只能用对应参数个数的构造方法
                    if (parameterCount != explicitArgs.length) {
                        continue;
                    }
                    // 不用再去BeanFactory中去查找Bean对象了,已经有了,同时当前正在遍历的构造方法就是可用的构造方法
                    argsHolder = new ArgumentsHolder(explicitArgs);
                }
                // 当前遍历的构造方法所需要的入参对象都找到了,根据参数类型和找到的参数对象计算出一个匹配值,值越小越匹配
                // 默认为Lenient,表示宽松模式
                int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
                        argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                // 值越小越匹配
                if (typeDiffWeight < minTypeDiffWeight) {
                    constructorToUse = candidate;
                    argsHolderToUse = argsHolder;
                    argsToUse = argsHolder.arguments;
                    minTypeDiffWeight = typeDiffWeight;
                    ambiguousConstructors = null;
                    // 值相等的情况下,记录一下匹配值相同的构造方法
                } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
                    if (ambiguousConstructors == null) {
                        ambiguousConstructors = new LinkedHashSet<>();
                        ambiguousConstructors.add(constructorToUse);
                    }
                    ambiguousConstructors.add(candidate);
                }
            }
            // 如果没有可用的构造方法,就取记录的最后一个异常并抛出
            if (constructorToUse == null) {
                // 有构造方法 通过参数找不到对应的Bean而抛出异常
                if (causes != null) {
                    UnsatisfiedDependencyException ex = causes.removeLast();
                    for (Exception cause : causes) {
                        // 记录压制的异常
                        this.beanFactory.onSuppressedException(cause);
                    }
                    // 把异常抛出
                    throw ex;
                }
                throw new BeanCreationException();
                // 有多个可用的构造方法且分数一样,并且不是宽松模式,则抛异常
            } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
                throw new BeanCreationException();
            }
            // 不是通过getBean()方法指定args,且找到了构造方法已经要用的入参对象,则缓存
            if (explicitArgs == null && argsHolderToUse != null) {
                argsHolderToUse.storeCache(mbd, constructorToUse);
            }
        }
        // 根据找到的构造方法和方法入参实例化对象,并将实例化的对象赋值给bw
        bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
        return bw;
    }
  • 先检查是否指定了具体的构造方法和构造方法参数值,或者在BeanDefinition中缓存了具体的构造方法或构造方法参数值,如果存在那么则直接使用该构造方法进行实例化
  • 如果没有确定的构造方法或构造方法参数值,那么
    • 如果没有候选的构造方法(chosenCtors = null),那么则找出类中所有的构造方法;
    • 如果只有一个无参的构造方法,那么直接使用无参的构造方法进行实例化;
    • 说明有多个可用的构造方法或者当前Bean需要自动通过构造方法注入;
    • 计算minNrOfArgs的值,根据所指定的构造方法参数值,确定所需要的最少的构造方法参数值的个数
    • 对所有的构造方法进行排序,public的方法排在最前面,都是public的情况下参数个数越多越靠前
    • 遍历每个构造方法,构造方法参数个数小于minNrOfArgs,则忽略该构造方法;
    • 如果调用getBean()方法时没有指定构造方法参数值,则先通过ParameterNameDiscoverer解析出参数名,然后根据参数类型和参数名称从容器中找到对应的Bean对象;
    • 如果调用getBean()方法时指定了构造方法参数值,那么就直接利用这些值;
    • 如果根据当前构造方法找到了对应的构造方法参数值,那么这个构造方法就是可用的,但是不一定这个构造方法就是最佳的,所以这里会涉及到是否有多个构造方法匹配了同样的值,这个时候就会用值和构造方法类型进行匹配程度的打分,找到一个最匹配的;
      • 默认采用Lenient宽松模式
      • 构造方法参数类型和找到的Bean对象完全匹配,得0分;
      • 构造方法参数类型是是找到的Bean对象的父类,得2分;
      • 构造方法参数类型是找到的Bean对象实现的接口,得1分;
      • 最后计算出得分,得分越小的越匹配。
    • 遍历完所有构造方法,若没有找到可用的构造方法,则抛出异常;
    • 缓存推断出来的构造方法。
  • 根据找到的构造方法和方法入参实例化对象。

@Bean的情况 

首先,Spring会把@Bean修饰的方法解析成BeanDefinition:

  • 如果方法不是static的,那么解析出来的BeanDefinition中:
    • factoryBeanName为AppConfig所对应的beanName,比如"appConfig"
    • factoryMethodName为对应的方法名,比如"userService"
    • factoryClass为AppConfig.class
  • 如果方法是static的,那么解析出来的BeanDefinition中:
    • factoryBeanName为 null
    • factoryMethodName为对应的方法名,比如"userService"
    • factoryClass也为AppConfig.class 

这和早期xml通过静态工厂定义Bean对象和实例工厂定义Bean对象的方式相匹配

<bean id="userService" factory-bean="appConfig" factory-method="creatUserService"/>

<bean id="userService" class="com.spring.AppConfig" factory-method="creatUserService"/>

instantiateUsingFactoryMethod

instantiateUsingFactoryMethod方法就是处理通过@Bean注解定义的Bean对象,其中确定FactoryMethod方法和方法所需参数的逻辑与autowireConstructor的逻辑大致相同。

    public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
        BeanWrapperImpl bw = new BeanWrapperImpl();
        this.beanFactory.initBeanWrapper(bw);
        Object factoryBean;
        Class<?> factoryClass;
        boolean isStatic;

        // 这里拿到的是factoryBeanName,而不是factoryMethodName,也就是@Bean所在类对象名称
        // 例如 appConfig
        String factoryBeanName = mbd.getFactoryBeanName();

        // factoryBeanName不为null的情况,对应@Bean标注的方法不是staic方法
        if (factoryBeanName != null) {
            if (factoryBeanName.equals(beanName)) {
                throw new BeanDefinitionStoreException();
            }

            // 这里拿到的factoryBean为AppConfig的代理对象
            factoryBean = this.beanFactory.getBean(factoryBeanName);
            if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
                throw new ImplicitlyAppearedSingletonException();
            }
            // 注册Bean对象之间的依赖关系
            this.beanFactory.registerDependentBean(factoryBeanName, beanName);
            // 这里拿到的factoryClass为AppConfig的代理对象的class
            factoryClass = factoryBean.getClass();
            isStatic = false;
            // factoryBeanName为null的情况,对应@Bean标注的方法是staic方法
        } else {
            if (!mbd.hasBeanClass()) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "bean definition declares neither a bean class nor a factory-bean reference");
            }
            factoryBean = null;
            factoryClass = mbd.getBeanClass();
            isStatic = true;
        }
        // 通过以上步骤确定了 factoryBean、factoryClass和isStatic的值

        // 接下来就是确定要使用哪个factoryMethod以及factoryMethod所需要的参数
        Method factoryMethodToUse = null;
        ArgumentsHolder argsHolderToUse = null;
        Object[] argsToUse = null;

        // 如果getBean()传入了args,则构造方法要使用的入参就已经确定好了
        if (explicitArgs != null) {
            argsToUse = explicitArgs;
        } else {
            Object[] argsToResolve = null;
            synchronized (mbd.constructorArgumentLock) {
                // 拿到指定或缓存的FactoryMethod
                factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
                if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
                    // 缓存的构造方法参数
                    argsToUse = mbd.resolvedConstructorArguments;
                    if (argsToUse == null) {
                        // beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference("orderService"));
                        argsToResolve = mbd.preparedConstructorArguments;
                    }
                }
            }
            if (argsToResolve != null) {
                // beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, new RuntimeBeanReference("orderService"));
                argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
            }
        }
        // 没有确定要使用的factoryMethod,或者确定了factoryMethod但是方法入参没有确定
        if (factoryMethodToUse == null || argsToUse == null) {
            // 拿到代理对象的目标对象 即AppConfig.class
            factoryClass = ClassUtils.getUserClass(factoryClass);
            // 记录所有的候选方法集合
            List<Method> candidates = null;
            // 只有一个FactoryMethod,则就使用这个唯一的FactoryMethod
            if (mbd.isFactoryMethodUnique) {
                if (factoryMethodToUse == null) {
                    factoryMethodToUse = mbd.getResolvedFactoryMethod();
                }
                if (factoryMethodToUse != null) {
                    candidates = Collections.singletonList(factoryMethodToUse);
                }
            }
            if (candidates == null) {
                candidates = new ArrayList<>();
                // 拿到类中所有的方法,包括继承的方法
                Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
                // 筛选出满足条件的FactoryMethod
                for (Method candidate : rawCandidates) {
                    if ((!isStatic || isStaticCandidate(candidate, factoryClass)) && mbd.isFactoryMethod(candidate)) {
                        candidates.add(candidate);
                    }
                }
            }
            // 如果筛选之后,只有一个可用的FactoryMethod,且不是通过getBean()指定args,且方法是无参的,则就使用该FactoryMethod了
            if (candidates.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
                Method uniqueCandidate = candidates.get(0);
                if (uniqueCandidate.getParameterCount() == 0) {
                    mbd.factoryMethodToIntrospect = uniqueCandidate;
                    synchronized (mbd.constructorArgumentLock) {
                        mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
                        mbd.constructorArgumentsResolved = true;
                        mbd.resolvedConstructorArguments = EMPTY_ARGS;
                    }
                    bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
                    return bw;
                }
            }
            // 如果筛选过后还有多个可用的FactoryMethod
            if (candidates.size() > 1) {
                // 则将FactoryMethod进行排序,public的方法排在最前面,都是public的情况下参数个数越多越靠前
                candidates.sort(AutowireUtils.EXECUTABLE_COMPARATOR);
            }
            ConstructorArgumentValues resolvedValues = null;
            // 默认为true
            boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);

            int minTypeDiffWeight = Integer.MAX_VALUE;
            Set<Method> ambiguousFactoryMethods = null;

            // 计算 minNrOfArgs 第一次为0
            int minNrOfArgs;
            if (explicitArgs != null) {
                minNrOfArgs = explicitArgs.length;
            } else {
                if (mbd.hasConstructorArgumentValues()) {
                    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
                    resolvedValues = new ConstructorArgumentValues();
                    minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
                } else {
                    minNrOfArgs = 0;
                }
            }
            Deque<UnsatisfiedDependencyException> causes = null;

            // 遍历所有的FactoryMethod
            for (Method candidate : candidates) {
                // 方法参数
                int parameterCount = candidate.getParameterCount();
                if (parameterCount >= minNrOfArgs) {
                    ArgumentsHolder argsHolder;
                    // 拿到所有参数的类型
                    Class<?>[] paramTypes = candidate.getParameterTypes();
                    if (explicitArgs != null) {
                        if (paramTypes.length != explicitArgs.length) {
                            continue;
                        }
                        argsHolder = new ArgumentsHolder(explicitArgs);
                    } else {
                        try {
                            String[] paramNames = null;
                            if (resolvedValues != null && resolvedValues.containsNamedArgument()) {
                                // 获取参数名解析器
                                // StandardReflectionParameterNameDiscoverer: 通过反射(1.8)获取方法参数名称
                                // LocalVariableTableParameterNameDiscoverer: 解析字节码本地变量表获得方法参数名称
                                ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
                                if (pnd != null) {
                                    // 解析参数名
                                    paramNames = pnd.getParameterNames(candidate);
                                }
                            }
                            // 根据参数类型和参数名,找到对应的Bean对象
                            argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring, candidates.size() == 1);
                        } catch (UnsatisfiedDependencyException ex) {
                            if (causes == null) {
                                causes = new ArrayDeque<>(1);
                            }
                            causes.add(ex);
                            continue;
                        }
                    }
                    // 当前遍历的构造方法所需要的入参对象都找到了,根据参数类型和找到的参数对象计算出一个匹配值,值越小越匹配
                    // 默认为严格模式
                    int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
                    // 值越小越匹配
                    if (typeDiffWeight < minTypeDiffWeight) {
                        factoryMethodToUse = candidate;
                        argsHolderToUse = argsHolder;
                        argsToUse = argsHolder.arguments;
                        minTypeDiffWeight = typeDiffWeight;
                        ambiguousFactoryMethods = null;
                        // 计算的值和已有的factoryMethod值相等,且是严格模式的计算方式,且参数个数也相同,且参数类型不相同
                    } else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight && !mbd.isLenientConstructorResolution() && paramTypes.length == factoryMethodToUse.getParameterCount() && !Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
                        // 则将这两个factoryMethod加入集合,再用其他方式选择
                        if (ambiguousFactoryMethods == null) {
                            ambiguousFactoryMethods = new LinkedHashSet<>();
                            ambiguousFactoryMethods.add(factoryMethodToUse);
                        }
                        ambiguousFactoryMethods.add(candidate);
                    }
                }
            }

            // 没有确定要使用的factoryMethod,或者确定了factoryMethod但是方法入参没有确定
            if (factoryMethodToUse == null || argsToUse == null) {
                // 根据factoryMethod方法参数依赖查找时有报错
                if (causes != null) {
                    UnsatisfiedDependencyException ex = causes.removeLast();
                    for (Exception cause : causes) {
                        this.beanFactory.onSuppressedException(cause);
                    }
                    throw ex;
                }
                // factoryMethod的返回值是void            
            } else if (void.class == factoryMethodToUse.getReturnType()) {
                throw new BeanCreationException();
                // 有多个相同的FactoryMethod
            } else if (ambiguousFactoryMethods != null) {
                throw new BeanCreationException();
            }
            // 不是调用getBean()方法指定的args的方式
            // 则缓存解析到的factoryMethod以及所需要的参数
            if (explicitArgs == null && argsHolderToUse != null) {
                mbd.factoryMethodToIntrospect = factoryMethodToUse;
                argsHolderToUse.storeCache(mbd, factoryMethodToUse);
            }
        }
        bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
        return bw;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值