@Autowired
关于 @Autowired
@Autowired 是 Spring 提供的注解,用来在 Spring 里面去实现 Bean 的依赖注入。
一说到 @Autowired,大多数人肯定会说,这个注解是根据类型来注入的。
但是经过实测,这种说法并不是很准确。@Autowired 也不仅仅是这么简单的。
本次测试使用 SpringBoot 2.2.0 版本。
(1) 当 Spring 容器中同类型的 bean 只存在一个时,@Autowired 是根据类型 ByType 来注入的,被注入的对象的名字可以随意,都能注入。
eg1:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() {
return new User();
}
}
@Service
public class TestService {
@Autowired
private User order; // 这里的属性名字随意,叫啥都行
@Autowired
private User pay; // 注入多次也都可以
}
(2) 当 Spring 容器中同类型的 bean 存在多个时,@Autowire 为 根据名称 ByName 的方式注入。ByName 是将 bean 单例池中的 key(bean 的名字)与被注入的成员变量的名进行匹配,而不是与类型进行匹配。
PS:相同类型的 Bean 会在 Spring 容器中存在多个,每个 Bean 的堆内存地址都不一样,即都是不同的对象。
eg2:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() {
return new User(); // 两个类型相同的 Bean,只是名字不同
}
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
return new User();
}
}
@Service
public class TestService {
@Autowired
private User user; // 注入 name = user 的 bean
@Autowired
private User user2; // 注入 name = user2 的 bean
}
运行如上代码,Spring 启动并不报错,使用成员变量也不会报错,注入成功。
eg3:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() {
return new User(); // 两个类型相同的 Bean,只是名字不同
}
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
return new User();
}
}
@Service
public class TestService {
@Autowired
private User user1; // 注入失败,编辑的时候,IDEA就给出报错提示了
@Autowired
private User order; // 注入失败,编辑的时候,IDEA就给出报错提示了
}
IDEA 给出的报错提示:
关于 required 属性
@Autowired 有一个 required 属性,其默认值是 true,表示强制要求 bean 实例的注入,在应用启动的时候,如果 Spring 容器里面不存在对应类型的 Bean,就会报错。当设置为 false 时,Spring 启动时不会检查是否存在对应类型。
那我们将 eg3 中的 @Autowried 添加 required = false 属性后,是否能够注入成功呢?
答案是否定的,依旧无法注入。
那如果 Spring 中不存在该类型的 Bean,可以注入成功吗?
eg4:
@Configuration
public class BeanConfiguration {
// 没有任何 Bean
}
@Service
public class TestService {
@Autowired(required = false)
private User user;
@Autowired(required = false)
private User user2;
}
运行上面代码发现,Spring 启动时并不会报错,不过注入的属性是 null,虽然注入成功,但是也没法使用。
关于 @Primary 注解
@Primary:当 Spring 中存在多个相同类型的 Bean 时,优先使用声明了 @Primary 的 Bean。
@Primary 和 @Bean 一起搭配使用。
eg5:
@Configuration
public class BeanConfiguration {
@Primary // 表明 name=user 的 bean 有最高优先级
@Bean("user")
public User user() {
return new User(); // 两个类型相同的 Bean,只是名字不同
}
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
return new User();
}
}
@Service
public class TestService {
@Autowired
private User user; // 注入 name = user 的 bean
@Autowired
private User user2; // 注入 name = user2 的 bean
}
那么对于上面的代码,user 和 user2 注入的是哪一个?都是注入的 user 吧,毕竟人家使用了 @Primary 注解。
但实测发现,也确实是这样,。
关于 @Qualifier 注解
(1) @Qualifier 可以根据 Bean 的名字来注入指定 Bean.
@Qualifier 和 @Autowired 一起搭配使用。
eg6:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
}
@Service
public class TestService {
@Qualifier(value = "user2") // 指定注入 user2 Bean
@Autowired
private User user;
@Qualifier(value = "user") // 指定注入 user Bean
@Autowired
private User user2;
}
如果是上面代码的这种方式,那么是根据属性名来匹配注入呢,还是根据 @Qualifier 注解呢?
实测如下:
看来是 @Qualifier 注解的优先级更高。
(2) 延伸:@Quarifier 的第二个作用是可以作为筛选的限定符,我们在写自定义的注解时,可以在其定义上增加@Qualifier,来筛选需要的对象.
Spring 提供了将多个类型相同的 Bean 以 List 形式注入的方式。
eg7:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
}
@Service
public class TestService {
@Autowired
private List<User> users = Collections.emptyList();
}
如上面代码所示,最后注入的的 users 中包含 user 和 user2 两个 Bean。
这是默认的注入,如果你只想注入其中一个 Bean,比如 users 中只想要 user2,那要怎么处理呢?
使用 @Quarifier 注解便很容易完成这个需要。eg8:
@Configuration
public class BeanConfiguration {
@Bean("user")
public User user() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
@Qualifier
@Bean("user2")
public User user2() { // 两个类型相同的 Bean,只是名字不同
User user = new User();
return user;
}
}
@Service
public class TestService {
@Qualifier // 选择性注入
@Autowired
private List<User> users = Collections.emptyList();
}
实测结果如下: