【JavaEE】Spring的开发要点总结(3)
在前面的代码里,我们获取Bean对象也比较麻烦:
本文章就是为了更方便地去获取Bean对象~
- 对象装配
- 也叫 对象注入
那么有没有对应的注解去实现这个功能呢?
Spring提供的三种实现方法:
- 属性注入
- 构造方法注入
- Setter注入
而这种非明文获取Bean对象的过程,就是DI
- 而之前就是DL
首先,先创建一个新的项目,这次用规范的写法(工程分层):
- 配置文件自己去配~
1. 属性注入
这是数据持久层的一个插入方法,而 这个方法理论上是要在service层去调用的
但是new对象的写法在Spring已经不用啦:
属性注入则可以更便捷获取Bean对象~
1.1 @Autowired注解
利用这个注解,就能有以下操作:
测试一下:
- new对象的方式不行,跟Bean对象是否加载存储到Spring中五无关~
1.2 依赖查找 VS 依赖注入
参考之前的文章:
在这里体现出来的一点就是,依赖查找依赖Bean的名称,而依赖注入则会自动匹配和找到Bean对象,注入到属性中
- 不是说依赖注入没有“查找”的过程,只是依赖注入重点在于注入
- 如果找到多个,则根据名称去匹配对应的Bean对象!
1.3 配合@Qualifier 筛选Bean对象
你不管三七二十一,就想要一个响当当的属性名:“userSuperDao”,但是没有这个名的Bean对象(现在有多个Bean)
你就可以利用这个注解:
1.4 属性注入的优缺点
参考链接: https://juejin.cn/post/7135235294265081887
- 通用性问题
- 测试困难
- 依赖项之间的耦合
- 运行时的验证困难
- 依赖关系的不清楚,复杂
- 我们这种简单地用,@Autowired注解在属性上,去注入的方式可能不适用与非IoC容器的
- 而Setter和构造方法注入是通过调用方法的,所以没有这个问题
- 设计原则问题:更容易违背单一设计原则
参考官方文档:Spring | Home
单一设计原则要求一个类应该只有一个引起改变的原因,即一个类应该只有一个主要责任。当使用属性注入时,可能会出现以下情况:
- 因为开销比较小,在这个类里有啥需要就写一个属性,涉及多个职责耦合
- 依赖关系不清楚,乱,说到底还是属性写太多,设计不单一
但是,开发就是这样,不会很完美,3这个点很难避开
- 有时候为了速度,牺牲耦合性的情况也有
- 比如一个页面的信息有分类的,有不同的职责
- 但是,如果访问这个页面,要去访问那么多个接口,就有很多次“三次握手四次挥手”了
- 实际场景实际分析!
2. Setter注入
顾名思义,借此模仿,就是Setter方法加对应的注解
2.1 @Autowired注解
这就自动在Spring中找到Bean对象,然后通过Setter注入给对应的成员变量~
- DI,是这样的
测试:
2.2 命名规则
命名规则跟属性注入基本一致,你可以理解为属性注入套了层皮,就是Setter注入
正好现在我有两个UserDao的Bean对象,来演示一下:
- 一个aaa,一个userDao
观察一下,再看答案:
- 跟方法名无关
- 跟属性名无关
- 跟方法的参数名有关
- 可以结合@Qualifier注解
2.3 Setter注入的优缺点
3. 构造方法注入
这是官方推荐的一种注入方式~
- 虽然如此,官方写的代码,用这个的不多🤣
- 虽然更加完美,但是写起来麻烦
(Spring 4.x 之后推荐的注入方式)
3.1 @Autowired注解
- 在构造方法上加上个@Autowired注解~
这也是标准的写法~
不标准的写法,不加@Autowired注解不会报错:
- 因为官方推荐,所以搞了点小特殊🤣
- 这个类如果只有一个构造方法的情况下,才是可以省略的!
- 空的构造方法还行,就相当于啥也不注入,至少在构造UserService3的时候可以调用这个方法
- 这个方法直接是不能调用了,因为不确定调用哪个构造方法,该注入啥
加上就不会有事:
原理就是:
- 框架在构造UserService的时候,会根据@Autowried去挑选构造方法,而参数的来源就是Bean对象
- 因此构造方法就会将这些Bean对象注入到属性上
所以不能有多个@Autowired修饰的构造方法:
3.2 命名规则
跟Setter注入一样!
- 只不过不能用@Qualifier注解!
- 这个类只有一个Bean对象,那么参数名无所谓
- 这个类有多个Bean对象,那么参数名必须要匹配对应的Bean对象的名称
3.3 构造方法注入的优缺点
常见的面试题就是三者的区别:就是把他们的使用和优缺点讲一下~
4. 另一个注入可以用的注解@Resource
这个可以直接替换@Autowired注解,用IDEA专业版的话,有些场景下,用@Autowired是会报错的~
- 但是属于误报,运行还是可以运行(设置把报错信息忽略掉)~
用法基本一致:
这也是个常见的面试题:@Autowired和@Resource的区别是什么?
4.1 来源不同
@Autowired来自Spring框架,而@Resource来自JavaEE规范
4.2 匹配机制不同
- @Autowired先进行类型匹配再用名称匹配
- 但是专业版在这个注解判断代码正确与否的时候,并不会进一步用名称去匹配
- 所以会误报
- @Resource先进行名称匹配再进一步用类型匹配
- 名称对不上,也会用类型去找,有多个Bean会报错,只有一个Bean就忽略名称的问题
- 当然误报的原因可能有很多,甚至不是单一的原因…
- IDEA兼容性不同~
4.3 参数不同
@Autowired只有一个参数,required,而@Resource没有这个参数,但是有很多其他的参数
4.4 @Resource多一个匹配Bean对象名称的方案
4.5 使用上的区别
@Resource不支持构造方法注入
5. 综合练习
补充: 无论怎么样,静态属性是无法被注入Bean的,因为静态属性的加载是在Spring之前的,即类加载的时候,是这个类通用的属性,而Bean对象是一个实例!难不成每次获取Bean对象,Spring都会注入覆盖这个值吗~
这不合理~
- 而依赖注入发生在你获取Bean对象的时候,Spring帮你构造实例的时候,而不是你自己new和设置的时候
- 所以在main方法中,还是要通过DL去获取Bean
要求:在Spring项目中,通过main方法获取到Controller类,在Controller类里调用Service类,在Service类中获取Dao类,在Dao类中的一个方法,用伪代码new一个User,进行返回,返回给main方法,打印user。
运行结果: