使用注解的方式注入bean实例,在两年前的开发中,还经常看到@Resource
注解,这个注解是基于JSR250标准的,现在基本很少看到使用了,取而代之的是@Autowired
注解,也是官方推荐的。随着spring boot的出现,很多开发小伙伴喜欢通过config配置类加载一些bean,在加载这些bean会依赖到其他的一些bean实例,这个时候又慢慢的开始有比较多的使用@Qualifier
注解和@Autowired
配合使用,但是从版本来看@Qualifier
注解早在spring2.5版本就已经存在了。当然注入的注解并不止这两种,@Primary
和@Inject
都会说到。在使用过程中不同的注解对bean注入有着不同的优先级,下面就一起来了解一下。
代码部分
实体类Monkey,用于被注入的一个bean。
public class Monkey {
public int age = 10;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Monkey(int age) {
this.age = age;
}
@Override
public String toString() {
return "Monkey{" +"age=" + age + '}';
}
}
配置加载类InjectionConfig
。
@Configuration
@ComponentScan(basePackages = {"com.zdydoit.core.injection"})
public class InjectionConfig {
@Bean
public Monkey monkey() {
return new Monkey(20);
}
@Bean("monkey2")
public Monkey monkey2() {
return new Monkey(30);
}
}
依赖Monkey
对象的InjectionService
类。
@Service
public class InjectionService {
@Autowired
private Monkey monkey;
public void print() {
System.out.println("==>" + monkey);
}
}
最后就是测试类InjectionTest
啦。
public class InjectionTest {
@Test
public void test() {
ApplicationContext app = new AnnotationConfigApplicationContext(InjectionConfig.class);
InjectionService service = app.getBean(InjectionService.class);
service.print();
}
}
代码部分就是如上,后面来开始依次来说这些注解的优先级。
@Autowried
只用@Autowired
注解的时候,这个就很简单了,首先会去IOC容器中找beanName为monkey的bean,如果找到直接注入,如果找不到就会报错。运行一下测试结果。
==>Monkey{age=20}
很好理解,不多做解释。
@Qualifier
这个注解需要注意的是,注解类里面只有一个字段name,这个name如果不给定一个值得话,会报错的,错误里面就是说这个name值为空,而且@AutoWired
注解的required字段为true。也就是这个Monkey注入是必须的,但是找不到对应的bean。
因此在这里使用的时候要注意给@Qualifier
的name字段要赋值。并且要将@Autowird
注解的required字段设置为false,防止没有对应的bean导致报错。使用需谨慎。
这里的使用方式就是将原来注入的方式改为如下:
@Autowired(required=false)
@Qualifier("monkey2")
private Monkey monkey;
得到的结果如下:
==>Monkey{age=30}
可以看的出来加上这个注解以后,不会去找beanName为monkey的实例,而是monkey2,这里还是要注意加上这个注解后,只会去找monkey2,没有备选。
@Primary
这个注解不是用在注入的时候,而是用在创建bean的使用,需要在创建的bean的方法上加上这个注解。在congfig配置类中新加入下面这段代码:
@Bean
@Primary
public Monkey monkey3(){
return new Monkey(40);
}
注入bean的代码将@Qualifier
注解去掉,如下:
@Autowired
private Monkey monkey;
看一下运行的结果:
==>Monkey{age=40}
这里可以知道,当存在同一类型的bean,其中有一个bean创建的时候加上了@Primary
注解后,在注入bean的时候,会优先选择这个被@Primary
修饰的bean。
@Resource、@Inject
这两个注解分别是基于JSR250标准和JSR330标准的,都可以用于注入bean实例,这里不做多的解释。但是@Inject
注解在使用的需要引入javax.inject
依赖如下:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
每个注解的基本使用都已经说过了,但是在多个注解组合使用的时候会出现什么情况呢,下面来说一个例子(只说一个,因为组合的方式有点多,都说没有太大的意义,后面会做总结)。
@Autowired、@Qualifier、@Primary注解同时存在
需要将配置类中的代码改成如下:
@Bean
public Monkey monkey() {
return new Monkey(20);
}
@Bean("monkey2")
public Monkey monkey2() {
return new Monkey(30);
}
@Bean
@Primary
public Monkey monkey3(){
return new Monkey(40);
}
将注入的代码改为如下:
@Qualifier("monkey2")
@Autowired(required = false)
private Monkey monkey;
运行的结果是如下:
==>Monkey{age=30}
这个结果可以看出来@Qualifier
的优先级很高,@Primary
注解也暗淡失色了。其实从日常生活中也可以很容易的理解,条件越苛刻,往往就会优先级更高一点。
总结
这个注解有很多的组合方式,感兴趣的可以去尝试一下,下面做一个总结啦。
- 当单独使用
@Autowired
首先会根据注入bean的名字去IOC容器中找,如果找不到,会根据当前注入类的类型去找,当找到一个的时候,很简单,直接注入,如果有多个,那就会出现报错。因为他也不知选谁。 - 当
@Autowired
和@Qualifier(name="demo")
组合使用的时候,只会到IOC容器中找beanName为demo的bean,找不到就注入null,如果这个时候@Autowired
的required字段为true那么悲催了,报错。 - 当
@Autowired
、@Qualifier(name="demo")
、@Primary
同时被使用的时候,@Qualifier(name="demo")
注解优先级最高,还是会去beanName为demo的bean,找不到就注入null。 - 当
@Autowired
和@Primary
同时使用,会优先注入@Primary
修饰的bean。 - 当
@Resource
和@Qaulifier
同时使用,@Qaulifier
不会起作用,依然采用默认的方式,按照注入的bean的名字从IOC容器中获取,获取不到就按照注入类的类型去找,找到一个就注入,找到多个就报错。 - 当
@Inject
和@Qaulifier
配合使用与@Autowired
和@Qaulifier
是相同的。 - 当
@Inject
和@Primary
同时使用,会优先注入@Primary
修饰的bean。 - 当
@Resource
和@Primary
同时使用,@Primary
不会起到作用,采用@Resource
默认的方式注入。从这一点和上面@Resource
和@Qaulifier
配合使用上,可以看出来@Resource
真的是油盐不进。
主要的匹配的规则上面都列出来,如果你想到更多新的组合,可以尝试一下(欢迎留言,说出你的组合)。
还有要再说一下@Inject
注解,他是需要引入第三方包javax.inject
,可以知道不依赖于spring,如果需要自定义容器的话,可以使用@Inject
注解实现注入。另外上面的Inject
注解的各种组合方式和@Autowired
的各种组合方式,出现的结果都是一样的,也可以看出@Inject
的兼容性。