Spring 中实现自动注入的几种方式
Spring 中实现自动装配的注解有以下几个:
-
@Autowired
、@Qualifier
、@Primary
、@Resource
、@Inject
;
一、@Autowired
Spring 中最常用的一个注解,当一个组件需要另一个组件作为属性的时候,我们可以通过两种方式对属性进行赋值,一种是通过构造方法,一种是通过 set
方法(类比),而这个注解使用的方法就是后者。
下面介绍该注解的特点:
- 首先是 按照类型 自动注入,适用于容器中只有一种该类型的组件;
- 如果存在多个相同类型的组件,则将属性名作为
id
查询容器中的组件并注入; - 默认属性对应的组件在容器中必须是存在的,如果想无论存在与否都注入可以令属性
required = false
; - 可以在该注解的基础之上使用
@Qualifier("bookDao")
注解指定要注入组件的id
,这时属性名的id
已失效; - 如果不使用上述注解指定
id
,存在多个相同类型的组件时也可以使用@Primary
注解设置Bean
的优先级为最优。
@Autowired(required = false)
@Qualifier("bookDao2")
private BookDao bookDao;
上面注入的组件的 id 值为 bookDao2
;
二、@Resource
与 @Autowired
不同,@Resource
注解是 按照属性名 自动注入,它属于 JSR250
规范;
该注解不支持 @Qualifier
、@Primary
的使用,但是可以使用它的 name
属性指定要注入组件的 id
值。
@Resource(name = "bookDao3")
private BookDao bookDao;
上面注入的组件的 id 值为 bookDao3
;
三、@Inject
要使用 @Inject
注解必须要先导包,它属于 JSR330
规范 :
<!-- inject 注解 -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
导包之后就可以使用了,该注解的效果和 @Autowired
的效果一样,只不过没有任何属性,所以功能有些欠缺,但是可以和另外两个注解配合使用。
@Inject
private BookDao bookDao;
上面注入的组件的 id 值为 bookDao
;
四、@Autowired 的使用方式
该注解主要是通过 BeanPostProcessor
的实现类 AutowiredAnnotationBeanPostProcessor
实现的。
该类及其父类重写了 postProcessBeforeInitialization
方法,在初始化 Bean 之前,先对属性进行赋值,从而实现自动注入。
1、Set 方法
该注解除了可以放在属性上面,还可以放在方法上面:
@Component
public class Boss {
private Car car;
public Car getCar() {
return car;
}
@Autowired
public void setCar(Car car) {
this.car = car;
}
}
可以放在 set
方法上面,他会自动的去 IOC 容器中找方法中的参数,这里的参数是 car
,所以他会去容器中找 car
这个类,然后创建一个对象完成赋值。
官方 3.X 建议使用该方式注入。
2、构造器
对于加在 IOC 容器中的组件,容器启动后会调用 无参构造器 创建对象进行初始化赋值操作。
我们也可以不使用默认的,我们提供一个有参构造器:
@Autowired
public Boss(Car car) {
this.car = car;
}
构造器要使用的组件,也都是从容器中获取。
所以也可以这么写:
public Boss(@Autowired Car car) {
this.car = car;
}
同时如果该类只有一个有参构造器,那么 @Autowired
注解 可以省略。
官方 4.X 开始建议使用该方式注入。
3、@Bean + 方法参数
我们可以不改变 Boss
这个类,即不在 Boss
中注入 Car
,而是在将 Boss
放入容器的时候注入它需要的参数 Car
。
@Bean
public Boss boss(@Autowired Car car) {
return new Boss();
}
这里的 @Autowired
可以省略,也是用的最多的一种方式。
五、使用 Spring 底层的组件
如果自己写的组件想要使用 Spring 底层的组件可以使用另一种方式 :比如想要使用 Spring 的 ApplicationContext
。
Spring
为我们提供了相关的接口,他们都是 xxxAware,比如 ApplicationContextAware
。
每一个接口都对应一个方法,我们可以在方法中获取 Spring 底层的组件,然后给成员变量赋值以获取相关组件。
public class Red implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
关于 Aware
的原理:
其实它还是使用了我们之前说过的 BeanPostProcessor
,每一个 Aware 都对应一个 AwareProcessor,这个 processor 正是BeanPostProcessor
的实现类,所以肯定会有一个 postProcessBeforeInitialization
方法,我们重点来看一下这个方法。
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null && (bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
在 invokeAwareInterfaces(bean);
方法中主要是下面的逻辑:
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
其实就是先判断是不是那几个 Aware 中的一个,如果是就赋值,我们能看到的就是在 初始化 的时候利用 后置处理器 完成赋值。
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(3)
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(2)
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)
- element-ui el-input只显示下划线
- 怎样去阅读源码,这篇文章值的你一读
- HTML5 Blob与ArrayBuffer、TypeArray和字符串String之间转换
- Mybatis 3 配置 Log4j
- 基于Three.js的360度全景--photo-sphere-viewer--简介
- MyBatis3-配置使用log4j输出日志
- nginx支持跨域访问
- nginx静态资源文件无法访问,403 forbidden错误
- vue.js如何在标签属性中插入变量参数
- SpringBoot解决ajax跨域问题
- WebBrowser(IE) 与 JS 相互调用
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- xmuC语言程序实践week 1 大作业
- 《01-背包问题-点菜》
- 模拟赛 2018 Benelux Algorithm Programming Contest (BAPC 18)(部分题)
- vue动态生成表单组件vue-form-maker
- 对顶堆求区间k小(大)数
- 祖传快读快写模板
- 进阶版树状数组
- Julia 生产环境就绪了吗?我们跟项目维护者聊了聊
- 《2017年内蒙古自治区第十二届大学生程序设计-超级密码》
- 知识图谱入门(三)
- xmuC语言程序实践week 2 大作业
- redis学习(二十三)
- Vue 轻量级后台管理系统基础模板
- R语言对混合分布中的不可观测与可观测异质性因子分析
- JavaScript同步、异步及事件循环