深入源码分析Spring中的构造器注入
# 1. 示例
构造器注入类,分别有三个构造器,一个是无参构造器,一个是注入一个bean的构造器,一个是注入两个bean的构造器:
public class constructorautowiredtest { private user user; private role role; public constructorautowiredtest() { } public constructorautowiredtest(user user) { this.user = user; } public constructorautowiredtest(user user, role role) { this.user = user; this.role = role; } public void test(){ system.out.println("user: "+user); system.out.println("role: "+role); }
# 2.@autowired注解依赖注入
determineconstructorsfrombeanpostprocessors方法将选择是否有适合的自动注入构造器,如果没有,将使用无参构造器实例化
**在没有@autowired注解的情况下:**
无参构造器将直接加入defaultconstructor集合中。 在构造器数量只有一个且有参数时,此唯一有参构造器将加入candidateconstructors集合中。
在构造器数量有两个的时候,并且存在无参构造器,将defaultconstructor(第一条的无参构造器)放入candidateconstructors集合中。
在构造器数量大于两个,并且存在无参构造器的情况下,将返回一个空的candidateconstructors集合,也就是没有找到构造器。
**在有@autowired注解的情况下:**
判断required属性:
true:先判断requiredconstructor集合是否为空,若不为空则代表之前已经有一个required=true的构造器了,两个true将抛出异常,再判断candidates集合是否为空,若不为空则表示之前已经有一个打了注解的构造器,此时required又是true,抛出异常。若两者都不为空将放入requiredconstructor集合中,再放入candidates集合中。
false:直接放入candidates集合中。 判断requiredconstructor集合是否为空(是否存在required=true的构造器),若没有,将默认构造器也放入candidates集合中。 最后将上述candidates赋值给最终返回的candidateconstructors集合。
# 3.总结
** 1、为什么写三个构造器(含有无参构造器),并且没有@autowired注解,spring总是使用无参构造器实例化bean?**
答:参照没有注解的处理方式: 若构造器只有两个,且存在无参构造器,将直接使用无参构造器初始化。若大于两个构造器,将返回一个空集合,也就是没有找到合适的构造器,那么参照第三节初始化bean的第一段代码createbeaninstance方法的末尾,将会使用无参构造器进行实例化。这也就解答了为什么没有注解,spring总是会使用无参的构造器进行实例化bean,并且此时若没有无参构造器会抛出异常,实例化bean失败。
** 2、为什么注释掉两个构造器,留下一个有参构造器,并且没有@autowired注解,spring将会使用构造器注入bean的方式初始化bean?**
答:参照没有注解的处理方式: 构造器只有一个且有参数时,将会把此构造器作为适用的构造器返回出去,使用此构造器进行实例化,参数自然会从ioc中获取bean进行注入。
**3、为什么写三个构造器,并且在其中一个构造器上打上@autowired注解,就可以正常注入构造器?**
答:参照有注解的处理方式: 在最后判断candidates适用的构造器集合是否为空时,若有注解,此集合当然不为空,且required=true,也不会将默认构造器集合defaultconstructor加入candidates集合中,最终返回的是candidates集合的数据,也就是这唯一一个打了注解的构造器,所以最终使用此打了注解的构造器进行实例化。
**4、两个@autowired注解就会报错,一定需要在所有@autowired中的required都加上false即可正常初始化?**
答:参照有注解的处理方式: 当打了两个@autowired注解,也就是两个required都为true,将会抛出异常,若是一个为true,一个为false,也将会抛出异常,无论顺序,因为有两层的判断,一个是requiredconstructor集合是否为空的判断,一个是candidates集合为空的判断,若两个构造器的required属性都为false,不会进行上述判断,直接放入candidates集合中,并且在下面的判断中会将defaultconstructor加入到candidates集合中,也就是candidates集合有三个构造器,作为结果返回。
**5、返回的构造器若有三个,spring将如何判断使用哪一个构造器呢?**
在后面spring会遍历三个构造器,依次判断参数是否是spring的bean(是否被ioc容器管理),若参数不是bean,将跳过判断下一个构造器,也就是说,例如上述两个参数的构造器其中一个参数不是bean,将判断一个参数的构造器,若此参数是bean,使用一个参数的构造器实例化,若此参数不是bean,将使用无参构造器实例化。也就是说,若使用@autowired注解进行构造器注入,required属性都设置为false的话,将避免无bean注入的异常,使用无参构造器正常实例化。若两个参数都是bean,则就直接使用两个参数的构造器进行实例化并获取对应bean注入构造器。 在这里最后说一点,从上面可以看出,若想使用构造器注入功能,最好将要注入的构造器都打上@autowired注解(若有多个需要注入的构造器,将所有@autowired中required属性都设置为false),若有多个构造器,只有一个构造器需要注入,将这个构造器打上@autowired注解即可,不用设置required属性。如果不打注解也是可以使用构造器注入功能的,但构造器数量只能为1,且代码可读性较差,读代码的人并不知道你这里使用了构造器注入的方式,所以这里我建议若使用构造器注入打上@autowired注解会比较好一点。
原文链接:https://blog.csdn.net/qq_41737716/article/details/85596817
推荐阅读
-
深入源码分析Spring中的构造器注入
-
深入源码分析Spring注解的实现原理---@Import
-
Spring中@Autowire注入的深入讲解
-
Spring AOP源码分析(三)Spring AOP中的一些基本接口及其概念
-
Spring源码分析-从@ComponentScan注解配置包扫描路径到IoC容器中的BeanDefinition,经历了什么(一)?
-
深入了解Spring源码4:懒加载的单例Bean获取过程分析
-
深入源码分析Spring中的构造器注入
-
源码分析:Spring是如何把Bean注册到IOC容器中的?
-
java定时任务_java中的任务调度之Timer定时器(案例和源码分析)
-
深入源码分析Spring注解的实现原理---@Import