Bootstrap

Spring源码分析之推断构造方法(一)

前面说过spring装配bean总体有两种模式,一种是手动装配,一种是自动装配(byName,byType,byContructor)。手动装配是一个bean引用到另外一个的bean情况下,这里我们通常是在xml或注解中手动加入的,但我敢肯定大多数都是用@Autowire注解指定注入bean。自动装配是不需要在代码中通过注解注入(需要set方法)或不需要在xml中配置property,spring就会帮我们做好。回到主题,创建一个对象,需要通过类的指定构造方法来实例化。那我们定义的bean,构造方法可能有多个,那Spring到底是怎样选择构造方法来实例化Bean呢?

 创建一个bean A

@Component
public class A {

    private B b;

    public void setB(B b) {
        this.b = b;
    }

    public A (){
        System.out.println("默认构造");
    }

    public A(B a){
        System.out.println("构造参数b");
    }
    public A(B b,C c){
        System.out.println("构造参数 b ,c");
    }

    public A(B b,C c ,D d){
        System.out.println("构造参数 b ,c,d");

    }
}

 我定义了四个构造方法,目的就是想知道Spring如何推断构造方法的。 下面直接通过源码,一探究竟

找到spring创建bean的方法 doGetBean方法,断点打到getSingle方法上然后条件是beanName == a,第一次执行这里getSingle可定返回空。然后找到createBean 方法,createBea方法调用doCreateBean,doCreateBean调用createBeanInstance,createBeanInstance调用 determineConstructorsFromBeanPostProcessors方法;

进入determineConstructorsFromBeanPostProcessors中,发现这里调用了bean的后置处理器BeanPostProcessor,其中推断构造方法,只有AutoWiredAnnotationBeanPostProcess这个处理器干了事情。

 

进去这个处理器中的determineCandidateConstructors方法,下面的逻辑就是推断构造方法的整个逻辑。下面进行详细分析,放出全局代码吧。

 if (candidateConstructors == null) {
            // Fully synchronized resolution now...
            synchronized (this.candidateConstructorsCache) {
                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                if (candidateConstructors == null) {
                    Constructor<?>[] rawCandidates;
                    try {
                        rawCandidates = beanClass.getDeclaredConstructors();
                    } catch (Throwable ex) {
                        throw new BeanCreationException("");
                    }
                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    Constructor<?> requiredConstructor = null;
                    Constructor<?> defaultConstructor = null;
                    Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                    int nonSyntheticConstructors = 0;
                    for (Constructor<?> candidate : rawCandidates) {
                        if (!candidate.isSynthetic()) {
                            nonSyntheticConstructors++;
                        } else if (primaryConstructor != null) {
                            continue;
                        }
                        AnnotationAttributes ann = findAutowiredAnnotation(candidate);
                        if (ann == null) {
                            Class<?> userClass = ClassUtils.getUserClass(beanClass);
                            if (userClass != beanClass) {
                                try {
                                    Constructor<?> superCtor =
                                            userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                    ann = findAutowiredAnnotation(superCtor);
                                } catch (NoSuchMethodException ex) {
                                    // Simply proceed, no equivalent superclass constructor found...
                                }
                            }
                        }
                        if (ann != null) {
                            if (requiredConstructor != null) {
                                throw new BeanCreationException(beanName,
                                        "Invalid autowire-marked constructor: " + candidate +
                                                ". Found constructor with 'required' Autowired annotation already: " +
                                                requiredConstructor);
                            }
                            boolean required = determineRequiredStatus(ann);
                            if (required) {
                                if (!candidates.isEmpty()) {
                                    throw new BeanCreationException(beanName,
                                            "Invalid autowire-marked constructors: " + candidates +
                                                    ". Found constructor with 'required' Autowired annotation: " +
                                                    candidate);
                                }
                                requiredConstructor = candidate;
                            }
                            candidates.add(candidate);
                        } else if (candidate.getParameterCount() == 0) {
                            defaultConstructor = candidate;
                        }
                    }
                    if (!candidates.isEmpty()) {
                        // Add default constructor to list of optional constructors, as fallback.
                        if (requiredConstructor == null) {
                            if (defaultConstructor != null) {
                                candidates.add(defaultConstructor);
                            } else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                                logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                        "': single autowire-marked constructor flagged as optional - " +
                                        "this constructor is effectively required since there is no " +
                                        "default constructor to fall back to: " + candidates.get(0));
                            }
                        }
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    } else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                        candidateConstructors = new Constructor<?>[]{rawCandidates[0]};
                    } else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                            defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                        candidateConstructors = new Constructor<?>[]{primaryConstructor, defaultConstructor};
                    } else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                        candidateConstructors = new Constructor<?>[]{primaryConstructor};
                    } else {
                        candidateConstructors = new Constructor<?>[0];
                    }
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }

 1.

Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass)

从candidateConstructorsCache 这个map中尝试获取key为beanClass的Constructor[]数组,如果为空,进行同步在获取一遍,同步主要考虑到了多线程情况 

2.

rawCandidates = beanClass.getDeclaredConstructors() 

得到A的声明的所有构造方法,4个

3.

 List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
定义要选举的构造方法集合,长度为bean构造方法的个数

4. 

Constructor<?> requiredConstructor = null;
这个是记录有@AutoWire()并且是require=true的构造方法,后面根据源码证明


Constructor<?> defaultConstructor = null;

记录默认的构造方法

 

Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);

这个是记录Kotlin处理的类,具体啥是Kotlin。。。。。不知道~,一般情况下这个记录都是空的,Spring做的还是很全面的。

 

int nonSyntheticConstructors = 0;

记录不是合成构造函数的个数,一般情况下都不是合成的。

5.

  遍历A声明的构造函数

AnnotationAttributes ann = findAutowiredAnnotation(candidate);

判断构造函数是不是被@Autowire或@Value注解

6.

因为我们的构造方法没有一个被@Autowire注解,所以为空。

有的话,就会判断@Autowire的require的属性是不是为true,如果为true,把这个contructor赋值给之前定义的变量requiredConstructor。然后把这个constructor放到candidates集合中。

此时同一类只能有一个构造函数被require=true修饰,如果有多个@Autowire,不管require的值是不是true,Spring 会直接抛异常。但可以有多个@Autowire(required=false)修饰的构造方法

    if (requiredConstructor != null) {
            throw new BeanCreationException(beanName,
                    "Invalid autowire-marked constructor: " + candidate +
                            ". Found constructor with 'required' Autowired annotation already: " +
                            requiredConstructor);
        }
        boolean required = determineRequiredStatus(ann);
        if (required) {
            if (!candidates.isEmpty()) {
                throw new BeanCreationException(beanName,
                        "Invalid autowire-marked constructors: " + candidates +
                                ". Found constructor with 'required' Autowired annotation: " +
                                candidate);
            }
            requiredConstructor = candidate;
        }
        candidates.add(candidate);

 

7.

空的话,会进行判断构造函数的参数长度是不是为0

else if (candidate.getParameterCount() == 0) {
   defaultConstructor = candidate;
}

如果条件满足的话,就把它赋值给变量defaultConstructor

 

8.

此时遍历流程已经还原完了,下面对遍历结果进行处理

首先判断 candidates集合是不是为空,从上面的遍历流程来看,只有在用@Autowire修饰的情况下,才放到candidates集合中。

8.1

如果candidates不为空,在判断requiredConstructor为空和defaultConstructor不为空把defaultConstructor放到candidates集合中。否则不把defaultConstructor放到candidates集合中。在把candidates拷贝到candidateConstructors数组中。

 if (!candidates.isEmpty()) {
            // Add default constructor to list of optional constructors, as fallback.
            if (requiredConstructor == null) {
                if (defaultConstructor != null) {
                    candidates.add(defaultConstructor);
                } else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                    logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                            "': single autowire-marked constructor flagged as optional - " +
                            "this constructor is effectively required since there is no " +
                            "default constructor to fall back to: " + candidates.get(0));
                }
            }
            candidateConstructors = candidates.toArray(new Constructor<?>[0]);
        }

8.2

如果candidates为空,再判断rawCandidates是不是只有一个构造方法,并且构造数的参数大于0,

else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
      candidateConstructors = new Constructor<?>[]{rawCandidates[0]};
}

8.3

再把推断的构造方法数组放到缓存map中。为了方便下次推断。

this.candidateConstructorsCache.put(beanClass, candidateConstructors);

 

9.

9.1

如果没有推断到构造方法,并且A不是自动注入模式的话(by AUTOWIRE_CONSTRUCTOR),会跳过这个方法。

9.2

如果有推断到构造方法或者bean的注入类型为自动注入的话,则执行。

因为我们的A不是自动注入模式的,并且推断的构造方法为空,会跳过下面的方法,下面的逻辑有点复杂,后面再说。

 

 

10.

由于构造方法没有推断到,会执行instantiateBean方法,constructorToUse = clazz.getDeclaredConstructor();这一行代码会把A类中默认无参的构造方法赋给constructorToUse

bd.resolvedConstructorOrFactoryMethod = constructorToUse;

再把它放到bd中的resolvedConstructorOrFactoryMethod属性上,方面下次获取。

最后执行实例化

return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
      KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));

 

总结:

1.spring首先拿到所有声明的构造方法,在判断有没有被@Autowire注解的,

          1.1.有,在判断requiredConstructor是不是为空,下面的判断执行完最后会放到candidates集合中

                  1.1.1.requiredConstructor不为空,直接抛异常。

                 1.1.2.requiredConstructor为空,在判断required

                          1.1.2.1.required=true,在判断candidates是不是为空,

                          1.1.2.2 candidates为空,requiredConstructor赋值

                          1.1.2.3.candidates不为空,直接抛异常。(构造函数不能被多个@Autowire(required=true)修饰)

 

        1.2.没有,在判断是不是无参,如果是,defaultConstructor赋值

 

 2.判断 candidates集合

         2.1.不为空,在判断requiredConstructor

              2.1.1 requiredConstructor为空,并且defaultConstructor不为空时,把默认的构造函数放到candidates集合中

         2.2.为空,在判断构造函数是不是只有一个并且带有参数

 

推断完成后,又会根据推断的构造函数和bean装配类型要不要进行二次推断,确保能够找到唯一一个构造方法并能成功实例化。。。。二次推断后面再细说吧。

;