@Autowired&@Qualifier@Primary
@Autowired
自动装配也就是依赖注入(DI
): 为容器中的组件自动装配其依赖其他组件;
- 先通过属性的类型匹配容器中的组件, 匹配到有且只有一个就自动注入属性
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有且只有一个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 自动注入时通过组件类型匹配 自动装配
@Autowired
private BookServiceImpl bookService;
}
- 如果在容器中匹配到多个同样类型的组件, 则再通过属性的名称匹配组件;
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookServiceImpl(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 自动注入时通过组件类型匹配 自动装配 如果找到多个, 则再通过属性名称查找 这里注入的一定是 id为 bookService的组件
@Autowired
private BookServiceImpl bookService;
}
- 其属性
required = true
表示 必须自动注入成功,Spring
才会进行下一步操作,例如初始化组件, 否则会报org.springframework.beans.factory.NoSuchBeanDefinitionException
异常, 表示没有找到对应属性的组件信息BeanDefinition
; 如果设置为false
,Spring
不会检测属性是否存在于容器中, 不管有没有注入成功, 都会进行下一步;
@Configuration
public class SpringConfig {
// Spring容器并没有注册BookServiceImpl 类相关的组件
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 容器中不存在任何BookServiceImpl 类型的组件, 此时bookService属性会为Null
@Autowired(required=false)
private BookServiceImpl bookService;
}
@Autowired
可以标注在构造器上,setter
方法上, 方法的参数上, 属性上;
/**1*/
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 标注在属性上
@Autowired
private BookServiceImpl bookService;
}
/**2*/
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
private BookServiceImpl bookService;
// 标注在setter方法上
@Autowired
public void setBookService(BookServiceImpl bookService) {
this.bookService = bookService;
}
}
/**3*/
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
private BookServiceImpl bookService;
// 标注在构造器上, 如果当前组件只有一个有参构造器时, @Autowired可以省略
@Autowired
public void BookAuthorServiceImpl (BookServiceImpl bookService) {
this.bookService = bookService;
}
}
/**4*/
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
private BookServiceImpl bookService;
// 标注在参数上, 如果当前组件只有一个有参构造器时, @Autowired可以省略
public void BookAuthorServiceImpl (@Autowired BookServiceImpl bookService) {
this.bookService = bookService;
}
}
/**5*/
// 在@Bean标注的方法上自动注入
@Configuration
public class SpringConfig {
// 这里的@Autowired可以省略,Spring会自动注入bookService
@Bean
public BookAuthorServiceImpl bookAuthorServiceImpl (@Autowired BookServiceImpl bookService){
BookAuthorServiceImpl bookAuthorServiceImpl = new BookAuthorServiceImpl();
bookAuthorServiceImpl.setBookService(bookService);
return bookAuthorServiceImpl;
}
}
public class BookAuthorServiceImpl {
private BookServiceImpl bookService;
public void BookAuthorServiceImpl (BookServiceImpl bookService) {
this.bookService = bookService;
}
}
@Qualifier
当自动装配时同样类型的匹配到多个组件, @Autowired
可以搭配@Qualifier
注解指定名称来匹配组件;
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookServiceImpl(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 自动注入时通过组件类型匹配 自动装配 如果找到多个, 由于@Qualifier注解指定了名称 这里注入的一定是 id为 bookServiceImpl的组件
@Qualifier("bookServiceImpl")
@Autowired
private BookServiceImpl bookService;
}
@Primary
让Spring
进行自动装配的时候, 默认使用被@Primary
注解标注的bean; 不能与@Qualifier
一起使用; 如果使用了@Qualifier
, 那么@Qualifier
优先级大于@Primary
;
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
@Primary
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookServiceImpl(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
// 自动注入时通过组件类型匹配 自动装配 如果找到多个, 由于@Primary注解指定首选bean 这里注入的一定是 id为 bookServiceImpl的组件
@Autowired
private BookServiceImpl bookService;
}
@Resource&@Inject
@Resource
Spring
支持java规范中的@Resource
注解, 可以和@Autowired
一样可以自动装配, 但只会根据名称匹配组件;且不能搭配@Primary
使用, 也不能指定required=false
;
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
@Primary
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookServiceImpl(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
//根据名称匹配 这里注入的是id为 bookService的组件
@Resource
private BookServiceImpl bookService;
}
@Inject
Spring
支持java规范中的@Inject
注解, 想要使用这个注解, 需要导入jar包依赖; 支持@Primary
注解搭配使用, 但不支持指定required=false
;
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Configuration
public class SpringConfig {
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookService(){
return new BookServiceImpl();
}
@Primary
@Bean // 容器中关于BookServiceImpl类型的组件有多个
public BookServiceImpl bookServiceImpl(){
return new BookServiceImpl();
}
}
@Service("bookAuthorService")
public class BookAuthorServiceImpl {
//根据名称匹配 这里注入的是id为 bookService的组件
@Resource
private BookServiceImpl bookService;
}
Aware
如果组件中需要注入Spring
底层的组件, 则可以将组件实现Aware
接口的子接口, 重写这些子接口的方法, 来自动注入Spring
底层的组件;
在组件实现这些Aware
接口后, Spring
会通过对应xxxAwareProcessor
后置处理器回调组件重写的方法, 将Spring
的底层组件注入 ;
@Service("bookService")
public class BookServiceImpl implements ApplicationContextAware{
// 重写ApplicationContextAware接口的setApplicationContext方法, 自动注入ApplicationContext
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
};
}
// xxxAwareProcessor后置处理器源码
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
// Spring在组件初始化之前调用的方法, 在bean的生命周期中学习过
@Override
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareInterfaces(bean);
return null;
}
}, acc);
}
else {
// 这里就是回调组件方法的地方
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
@Profile
使用此注解可以指定特定环境下才注入组件; @Profile("default")
表示默认使用此bean
@Configuration(value="config")
@PropertySource({"classpath:application.properties"})
public class SpringConfig {
@Value("${db.url}")
private String url;
@Value("${db.user}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.driverClass}")
private String driverClass;
// 在开发环境下注册
@Profile("dev")
@Bean
public DataSource dataSourceDev() throws Exception {
Properties properties = new Properties();
properties.put("url", url);
properties.put("username", username);
properties.put("password", password);
properties.put("driverClassName", driverClass);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
return dataSource;
}
// 在测试环境下注注册
@Profile("test")
@Bean
public DataSource dataSourceTest() throws Exception {
Properties properties = new Properties();
properties.put("url", url);
properties.put("username", username);
properties.put("password", password);
properties.put("driverClassName", driverClass);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
return dataSource;
}
// 在生产环境下注册
@Profile("pro")
@Bean
public DataSource dataSourcePro() throws Exception {
Properties properties = new Properties();
properties.put("url", url);
properties.put("username", username);
properties.put("password", password);
properties.put("driverClassName", driverClass);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
return dataSource;
}
}
public class Test {
@org.junit.Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 设置容器的环境为开发环境
context.getEnvironment().setActiveProfiles("dev");
// 注册配置类
context.register(SpringConfig.class);
// 刷新容器
context.refresh();
// 这里被注册的DataSource一定是dataSourceDev
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String string : beanDefinitionNames) {
System.err.println(string);
}
context.close();
}
}