Spring依赖注入
Spring依赖注入
spring依赖注入包括三种:1.setter注入,2.构造器注入,3.属性注入,
1.基于构造器注入
1 |
|
2.基于setter注入
1 |
|
3.基于Filed(注解)注入
1 |
|
我们使用最多的方式就是属性注入的方式:
- 注入方式非常简单:加入要注入的字段,附上
@Autowired
,即可完成。- 使得整体代码简洁明了,看起来美观大方
4.spring为什么推荐构造器注入方式?
先来看看Spring在文档里怎么说:
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.”
简单的翻译一下:这个构造器注入的方式能够保证注入的组件不可变,并且确保需要的依赖不为空。此外,构造器注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。与此同时,从代码质量的角度来看,一个巨大的构造方法通常代表着出现了代码异味,这个类可能承担了过多的责任。
对于这个类可能承担了过多的责任这个问题,说明你的类当中有太多的责任,那么你要好好想一想是不是自己违反了类的单一性职责原则,从而导致有这么多的依赖要注入。
依赖不可变:其实说的就是final关键字。
依赖不为空(省去了我们对其检查):当要实例化UserServiceImpl的时候,由于自己实现了有参数的构造函数,所以不会调用默认构造函数,那么就需要Spring容器传入所需要的参数,所以就两种情况:1、有该类型的参数->传入,OK 。2:无该类型的参数->报错。
完全初始化的状态:这个可以跟上面的依赖不为空结合起来,向构造器传参之前,要确保注入的内容不为空,那么肯定要调用依赖组件的构造方法完成实例化。而在Java类加载实例化的过程中,构造方法是最后一步(之前如果有父类先初始化父类,然后自己的成员变量,最后才是构造方法),所以返回来的都是初始化之后的状态。
5.@Autowired、@Resource、@Inject
Spring 支持使用@Autowired
, @Resource
,
@Inject
三个注解进行依赖注入。那@Autowired和@Resource以及@Inject等注解注入有何区别?
5.1 @Autowired
在Spring 2.5 引入了 @Autowired 注解:
1 |
|
从Autowired注解源码上看,可以使用在下面这些地方:
1 |
|
- 字段属性
1 |
|
- 构造函数,方法参数
1 |
|
- 方法
1 |
|
将@Autowired写在被注入的成员变量上,setter或者构造器上,就不用再xml文件中配置了。
如果有多个类型一样的Bean候选者,则默认根据设定的属性名称进行获取。如 HelloDao 在Spring中有 helloWorldDao 和 helloDao 两个Bean候选者。
首先根据类型获取,发现多个HelloDao,然后根据helloDao进行获取,如果要获取限定的其中一个候选者,结合@Qualifier进行注入。
1 |
|
注入名称为helloWorldDao 的Bean组件。@Qualifier("XXX") 中的 XX是 Bean 的名称,所以 @Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。
注入名称为helloWorldDao
的Bean组件。@Qualifier("XXX")
中的 XX是 Bean 的名称,所以
@Autowired
和 @Qualifier
结合使用时,自动注入的策略就从 byType 转变成 byName 了。
多个类型一样的Bean候选者,也可以@Primary
进行使用,设置首选的组件,也就是默认优先使用哪一个。
注意:使用@Qualifier 时候,如何设置的指定名称的Bean不存在,则会抛出异常,如果防止抛出异常,可以使用:
1 |
|
举例:
声明一个接口UserDao与2个实现类UserDaoImpl、UserDaoImpl2,如下:
UserDao:
1 |
|
UserDaoImpl:
1 |
|
UserDaoImpl2:
1 |
|
UserServiceImpl:
1 |
|
然后通过测试类:
1 |
|
就会发现控制台报错:
1 |
|
加上@Qualifier
注解,:
1 |
|
则运行正常:
1 |
|
- 简单总结:
1、@Autowired是Spring自带的注解,通过AutowiredAnnotationBeanPostProcessor
类实现的依赖注入
2、@Autowired可以作用在CONSTRUCTOR、METHOD、PARAMETER、FIELD、ANNOTATION_TYPE
3、@Autowired默认是根据类型(byType )进行自动装配的
4、如果有多个类型一样的Bean候选者,需要指定按照名称(byName )进行装配,则需要配合@Qualifier。
指定名称后,如果Spring IOC容器中没有对应的组件bean抛出NoSuchBeanDefinitionException。也可以将@Autowired中required配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛异常。
如果容器中有同种类型的多个实现,使用@Autowired则会抛出NoUniqueBeanDefinitionException异常,存在多个实现类会不知道选择哪一个而报错。所以说,存在多个实现类的情况,不能用byType 的形式。
5.2 @Resouce
- Resource注解源码
1 |
|
从Resource注解源码上看,可以使用在下面这些地方:
1 |
|
name 指定注入指定名称的组件。
- 字段属性
1 |
|
同理,如果有多个候选bean,则也会抛出NoUniqueBeanDefinitionException异常
也可以直接指定注入的bean,如:
1 |
|
name 的作用类似 @Qualifier,所以Autowired
- 简单总结:
1、@Resource是JSR250规范的实现,在javax.annotation包下
2、@Resource可以作用TYPE、FIELD、METHOD上
3、@Resource是默认根据属性名称进行自动装配的,如果有多个类型一样的Bean候选者,则可以通过name进行指定进行注入
5.3 @Inject
- Inject注解源码
1 |
|
从Inject注解源码上看,可以使用在下面这些地方:
1 |
|
- 字段属性
1 |
|
同理,如果有多个候选bean,则也会抛出NoUniqueBeanDefinitionException异常
也可以直接指定注入的bean,如:
1 |
|
name 的作用类似 @Qualifier,所以Autowired
- 简单总结:
1、@Inject是JSR330 (Dependency Injection for Java)中的规范,需要导入javax.inject.Inject jar包 ,才能实现注入
2、@Inject可以作用CONSTRUCTOR、METHOD、FIELD上
3、@Inject是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Named;
6.@Autowired、@Resource、@Inject总结
1、@Autowired是Spring自带的,@Resource是JSR250规范实现的,@Inject是JSR330规范实现的。
2、@Autowired、@Inject用法基本一样,不同的是@Inject没有required属性。
3、@Autowired、@Inject是默认按照类型匹配的,@Resource是按照名称匹配的。
4、@Autowired如果需要按照名称匹配需要和@Qualifier一起使用,@Inject和@Named一起使用,@Resource则通过name进行指定。
7.Read more
:lollipop::https://pdai.tech/md/spring/spring-x-framework-ioc.html
:lollipop::https://www.cnblogs.com/diandianquanquan/p/11518365.html
博客说明
文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,不用于任何的商业用途。如有侵权,请联系本人删除。谢谢!