深入源码分析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中的构造器注入的更多相关文章
- angular源码分析:angular中脏活累活承担者之$parse
我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...
- Vue.js 源码分析(八) 基础篇 依赖注入 provide/inject组合详解
先来看看官网的介绍: 简单的说,当组件的引入层次过多,我们的子孙组件想要获取祖先组件的资源,那么怎么办呢,总不能一直取父级往上吧,而且这样代码结构容易混乱.这个就是这对选项要干的事情 provide和 ...
- 从源码分析 Spring 基于注解的事务
在spring引入基于注解的事务(@Transactional)之前,我们一般都是如下这样进行拦截事务的配置: <!-- 拦截器方式配置事务 --> <tx:advice id=&q ...
- requirejs源码分析: config中shim
shim处理的源码: //Merge shim if (cfg.shim) { eachProp(cfg.shim, funct ...
- Tomcat源码分析----eclipse中搭建源码环境
前提:JDK,至少1.7,ant,要设置ANT_HOME环境变量,需要再classpath中增加ant的lib目录,在path变量中增加ant的bin目录 1.官网下载tomcat源码包:apache ...
- [Tomcat源码分析] Eclipse中搭建Apache Tomcat源码调试环境
网上很多文章都推荐使用Ant下载编译,但本地实践中屡屡失败,无法下载. 后来参考 https://blog.csdn.net/xiongyouqiang/article/details/7894107 ...
- 【Java入门提高篇】Day23 Java容器类详解(六)HashMap源码分析(中)
上一篇中对HashMap中的基本内容做了详细的介绍,解析了其中的get和put方法,想必大家对于HashMap也有了更好的认识,本篇将从了算法的角度,来分析HashMap中的那些函数. HashCod ...
- Kibana6.x.x源码分析--JavaScript中 "!~" 这样的符号是啥意思?
看到源码中有一段JS代码不太懂,如下: 里面这个 "!~" 符号看到后有点儿方啊O__O "…,毛线意思? [查资料,解释如下]: indexOf returns -1 ...
- Java入门到精通——框架篇之Spring源码分析Spring两大核心类
一.Spring核心类概述. Spring里面有两个最核心的类这是Spring实现最重要的部分. 1.DefaultListableBeanFactory 这个类位于Beans项目下的org.spri ...
随机推荐
- Linux常用命令之info、cal、echo命令
info命令,是Linux下info格式的帮助指令 执行man info可以查看info命令的 语法 info(选项)(参数) 选项 -d:添加包含info格式帮助文档的目录: -f:指定要读取的in ...
- Html中使用Cookie取值赋值
//设置Cookie function setCookie(name, value) { var Days = 1; var exp = new Date(); exp.setTime(exp.get ...
- Js基础知识(五) - 前端性能优化总结
前端性能优化总结 资源优化 缓存 最好的资源优化就是不加载资源.缓存也是最见效的优化手段.说实话,虽然说客户端缓存发生在浏览器端,但缓存主要还是服务端来控制,与我们前端关系并不是很大.但还是有必要了解 ...
- 15-资源等待类型sys.dm_os_wait_stats
一.总结 1.网址 https://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/ ...
- 如何使用Spring Securiry实现前后端分离项目的登录功能
如果不是前后端分离项目,使用SpringSecurity做登录功能会很省心,只要简单的几项配置,便可以轻松完成登录成功失败的处理,当访问需要认证的页面时,可以自动重定向到登录页面.但是前后端分离的项目 ...
- Spring 初探(二) AOP 图集
Spring AOP属于第二代AOP.采用Java作为AOP的实现语言(AOL),采用动态代理机制和字节码生成技术实现. 代理设计模式 ISubject 对被访问者或者被访问资源的抽象,某些场景下不使 ...
- mysql优化(下)
优化SQL语句:(1)不要使用 select *(2)尽量在where字段上添加索引:(3)模糊查询中%前置不能使用索引,比如 like ‘%a’;(4)使用or语句时,两侧语句都有索引时才使 ...
- 微信小程序mpvue项目使用WuxWeapp前端UI组件
前言:这是一篇简单粗暴的使用指南 在最近的小程序项目里前端UI框架最后选择使用WuxWeapp,这篇文章记录一下如何在小程序mpvue项目中使用该UI组件. 步骤一:下载源码 (地址在这里)主要是里面 ...
- Tiling_easy version
Tiling_easy version 思路:关于dp这种东西,有一点必须要想明白,就是状态与状态之间的转换关系,就比如说要求5个骨牌的方案数,因为有两种骨牌,那么可以用dp[3]+两个横着的骨牌或者 ...
- python-numpy-1
mean() mean() 函数定义: numpy.``mean(a, axis=None, dtype=None, out=None, keepdims=<class numpy._globa ...