问题
当我在创建一个Bean的时候,肯定是需要调用构造方法,如果有默认的就直接默认的,如果没有默认的,而且只有一个,就会调用这个构造方法,如果有两个,但是都不是默认的,自己也没有指定,就会抛异常,如果指定了,就用指定的
如果自己指定了,那个优先级就是最高的
源码解析
主要就是bean的实例化
- 这个方法比较长,分段分析
- 缓存(主要是 为了 原型bean 多次创建时,更快)
-
// 一个原型BeanDefinition,会多次来创建Bean,那么就可以把该BeanDefinition所要使用的构造方法缓存起来,避免每次都进行构造方法推断 boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; // autowireNecessary表示有没有必要要进行注入,比如当前BeanDefinition用的是无参构造方法,那么autowireNecessary为false,否则为true,表示需要给构造方法参数注入值 autowireNecessary = mbd.constructorArgumentsResolved; } } }
- 这个 args 是==》 getBean中传的args,这个其实是指定构造方法的参数中,如果自己指定了,那就没必要再去管缓存了,直接根据参数,找到那个构造方法,直接调用即可
- BD的resolvedConstructorOrFactoryMethod(类型是Executable 是 Method的父类),其实就是缓存的构造方法
- 如果有缓存的构造方法,就将有缓存的打开(resolved = true;)
-
autowireNecessary = mbd.constructorArgumentsResolved;
-
这行代码是为了确定这个缓存的构造方法的参数情况,如果是无参的,就直接false,不需要注入,如果是有参数,那就需要去找到参数并且注入,这个就为true
-
if (resolved) { // 如果确定了当前BeanDefinition的构造方法,那么看是否需要进行对构造方法进行参数的依赖注入(构造方法注入) if (autowireNecessary) { // 方法内会拿到缓存好的构造方法的入参 return autowireConstructor(beanName, mbd, null, null); } else { // 构造方法已经找到了,但是没有参数,那就表示是无参,直接进行实例化 return instantiateBean(beanName, mbd); } }
-
如果有缓存,就判断是不是需要参数,不需要就直接实例化,需要再去找
-
-
如果没有缓存,就开始了推断构造方法(找构造方法)
-
// 提供一个扩展点,可以利用SmartInstantiationAwareBeanPostProcessor来控制用beanClass中的哪些构造方法 // 比如AutowiredAnnotationBeanPostProcessor会把加了@Autowired注解的构造方法找出来,具体看代码实现会更复杂一点 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); // 如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入 // 如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法 // 如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了 // 如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // Preferred constructors for default construction? ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // No special handling: simply use no-arg constructor. // 不匹配以上情况,则直接使用无参构造方法 return instantiateBean(beanName, mbd);
-
determineConstructorsFromBeanPostProcessors(beanClass, beanName);
-
这个就是最后调的AutowiredAnnotationBeanPostProcessor类(非常熟悉)的determineCandidateConstructors方法
-
这个方法的逻辑有一点点绕(但是慢慢看,是可以看懂的)
-
大概就是
-
获取到所有的构造方法,并遍历
-
判断这个构造方法是否加了@Autowired的注解
-
加了
-
会获得这个注解的required的值
-
就是 所有加了这个注解的构造方法,如果其中出现一个为true,就会报错
-
但是只有一个构造方法加了这个注解,true不会报错
-
多个,要么都是false,出现true就会报错
-
一个 ,无论true或者false都不会报错
-
-
会将这些加了注解的构造方法放到candidates这个集合
-
如果有无参的构造方法(并且没有加注解),就会将这个方法打个标记
-
遍历就结束了
-
开始筛选
-
如果candidates这个集合不为空,
-
还没找到一个required为true的,但是找到了一个,无参的构造方法,就会将无参的加到这个集合中
-
如果找到了一个required为true的,那就只有这一个是有效的,candidates转为数组(就和默认的构造方法没有关系了)
-
-
如果candidates为空(就是没有一个构造方法加注解)
-
但是这个类的所有构造方法只有一个,还必须有参数,才会列为有效的构造方法
-
以上都不满足,就会返回null(代表,一个有效的都没有)
-
-
-
-
得到了ctros,如果是null,其实就会去找无参构造方法去创建对象,没找到就会抛异常(这个是兜底的)就是这个方法instantiateBean
-
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); }
-
如果这四个条件满足其一就会开始找了
-
如果推断出来了构造方法,则需要给构造方法赋值,也就是给构造方法参数赋值,也就是构造方法注入
如果没有推断出来构造方法,但是autowiremode为AUTOWIRE_CONSTRUCTOR,则也可能需要给构造方法赋值,因为不确定是用无参的还是有参的构造方法
如果通过BeanDefinition指定了构造方法参数值,那肯定就是要进行构造方法注入了
如果调用getBean的时候传入了构造方法参数值,那肯定就是要进行构造方法注入了-
开始注入
-
autowireConstructor
-
-
autowireConstructor
上面分析:ctros 要么是 null 只有一个 要么有多个
一个和多个 就会进入autowireConstructor 方法,其他的三个条件,大部分情况下都不符合
autowireConstructor这个方法也是超级无敌长