深入源码分析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); }

# [email protected]注解依赖注入

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

原文地址:https://www.cnblogs.com/chen-chen-chen/p/11619737.html

时间: 2024-10-11 21:47:35

深入源码分析Spring中的构造器注入的相关文章

jQuery源码分析-jQuery中的循环技巧

Js代码   作者:nuysoft/JS攻城师/高云 QQ:47214707 EMail:[email protected] 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 前记:本文收集了jQuery中出现的各种遍历技巧和场景 Js代码   // 简单的for-in(事件) for ( type in events ) { } Js代码   // 缓存length属性,避免每次都去查找length属性,稍微提升遍历速度 // 但是如果遍历HTMLCollection时,性能提升非常

【Spring】从源码分析Spring配置文件的加载

使用Spring必须在web.xml中写如下配置: <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-valu

从源码分析 Spring 基于注解的事物

在spring引入基于注解的事物(@Transactional)之前,我们一般都是如下这样进行拦截事物的配置: <!-- 拦截器方式配置事物 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation=&q

[Tomcat源码分析] Eclipse中搭建Apache Tomcat源码调试环境

网上很多文章都推荐使用Ant下载编译,但本地实践中屡屡失败,无法下载. 后来参考 https://blog.csdn.net/xiongyouqiang/article/details/78941077 总算把调试环境搭建完成. 以下文章几乎完全copy上述网址,但稍作延展. 下载源码 官网直接下载源码 http://tomcat.apache.org/download-70.cgi 源码导入到Eclipse中 第1步:Eclipse中新建一个Java Project,例如名称可以是Tomcat

Java入门到精通——框架篇之Spring源码分析Spring两大核心类

一.Spring核心类概述. Spring里面有两个最核心的类这是Spring实现最重要的部分. 1.DefaultListableBeanFactory 这个类位于Beans项目下的org.springframework.beans.factory.support包下. XmlBeanFactory(位于org.springframework.beans.factory.xml包)继承自DefaultListableBeanFactory,而DefaultListableBeanFactory

5. SOFAJRaft源码分析— RheaKV中如何存放数据?

概述 上一篇讲了RheaKV是如何进行初始化的,因为RheaKV主要是用来做KV存储的,RheaKV读写的是相当的复杂,一起写会篇幅太长,所以这一篇主要来讲一下RheaKV中如何存放数据. 我们这里使用一个客户端的例子来开始本次的讲解: public static void main(final String[] args) throws Exception { final Client client = new Client(); client.init(); //get(client.get

Spring 循环引用(二)源码分析

Spring 循环引用(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) Spring 循环引用相关文章: <Spring 循环引用(一)一个循环依赖引发的 BUG>:https://www.cnblogs.com/binarylei/p/10325698.html <Spring 循环引用(二)源码分析>:https://www.cnblogs.com/binarylei/p/1032604

Spring IOC源码分析之-刷新前的准备工作

目录 ClassPathXmlApplicationContext的注册方式 加载父子容器 配置路径解析 容器刷新 刷新容器之刷新预处理 ClassPathXmlApplicationContext的注册方式 源码分析基于Spring4.3 从ClassPathXmlApplicationContext入口,最终都会调用到 /* * 使用给定父级创建新的ClassPathXmlApplicationContext,从给定的XML文件加载定义信息. * 加载所有的bean 定义信息并且创建所有的单

Spring源码分析专题——目录

Spring源码分析专题 -- 阅读指引 IOC容器 Spring源码分析专题 -- IOC容器启动过程(上篇) Spring源码分析专题 -- IOC容器启动过程(中篇) Spring源码分析专题 -- IOC容器启动过程(下篇) Spring源码分析专题 -- IOC容器依赖注入 SpringMVC Spring源码分析专题 -- SpringMVC IOC容器依赖注入 Spring源码分析专题 -- SpringMVC原理分析 Spring源码分析专题 -- SpringAOP源码分析 S