一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
DI相关注解
如果一个bean已经放入Spring容器中了。那么我们可以使用下列注解实现属性注入,让Spring容器帮我们完成属性的赋值。
@Value
主要用于String,Integer等可以直接赋值的属性注入。不依赖setter方法,支持SpEL表达式。
例如:
@Service("userService")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Value("199")
private int num;
@Value("好好学习")
private String str;
@Value("#{19+3}")
private Integer age;
public void show() {
userDao.show();
}
}
@AutoWired
一个 Bean 要依赖另一个 Bean,在 xml 中可以声明 ref 属性,用注解就可以使用 @AutoWired
在 Bean 中直接在 属性 / setter 方法 上标注 @Autowired 注解,IOC 容器会按照属性对应的类型,从容器中找对应类型的 Bean 赋值到对应的属性上,实现自动注入。
Person :
@Component
public class Person {
private String name = "administrator";
// setter
Dog :
@Component
public class Dog {
@Value("dogdog")
private String name;
private Person person;
// toString() ......
给Dog注入Person的三种方式
对于 @Autowired 的使用,只需要在属性上标注即可:
@Component
public class Dog {
// ......
@Autowired
private Person person;
也可以使用构造器注入方式:
@Component
public class Dog {
// ......
private Person person;
@Autowired
public Dog(Person person) {
this.person = person;
}
亦可以使用 setter 方法注入:
@Component
public class Dog {
// ......
private Person person;
@Autowired
public void setPerson(Person person) {
this.person = person;
}
编写启动类,把上面的 Person 和 Dog 都扫描进 IOC 容器,之后取出 Dog 并打印:
public class InjectComplexFieldAnnoApplication {
public static void main(String[] args) throws Exception {
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.linkedbear.spring.basic_di.d_complexfield.bean");
Dog dog = ctx.getBean(Dog.class);
System.out.println(dog);
}
}
运行,打印 Dog ,发现 Dog 里已经依赖了 Person :
Dog{name='dogdog', person=Person{name='administrator'}}
注入的Bean不存在
将 Person 上面的 @Component 暂时的注释掉,此时 IOC 容器中应该没有 Person 了
这时就会报错
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.linkedbear.spring.basic_di.d_autowired.bean.Person' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
本来想找一个类型为 Person 的 Bean ,但一个也没找到@Component 注解被注释掉了,自然就不会注册了。如果出现这种情况下又不想让程序抛异常,就需要在 @Autowired 注解上加一个属性:required = false 。
@Autowired(required = false)
private Person person;
输出
Dog{name='dogdog', person=null}
@Qualifier
如果相同类型的bean在容器中有多个时,单独使用@AutoWired就不能满足要求,这时候可以再加上@Qualifier来指定bean的名字从容器中获取bean注入。
@Autowired
@Qualifier("userDao2")
private UserDao userDao;
注意:该直接不能单独使用。单独使用没有作用,必须配合 @Autowired 使用
【面试题】@Autowired注入的原理逻辑
先拿属性对应的类型,去 IOC 容器中找 Bean ,如果找到了一个,直接返回;如果找到多个类型一样的 Bean , 把属性名拿过去,跟这些 Bean 的 id 逐个对比,如果有一个相同的,直接返回;如果没有任何相同的 id 与要注入的属性名相同,则会抛出 NoUniqueBeanDefinitionException 异常。