概述
Spring容器能够通过检查ApplicationContext
中的内容来实现依赖自动装配
.
自动转配的模式
Spring IoC定义了几种装配模式可供选择:
模式 | 解释 |
---|---|
no | 不开启自动装配 |
byName | 通过名称自动装配, 在容器中查找名称然后装配 |
byType | 通过类型自动装配, 容器在内部查找匹配的类型进行自动装配, 如果存在多个会引发致命错误, 如果不村子一个则不会报错 |
constructor | 通过构造函数自动装配, 和byType类似, 如果不存在bean, 则会报错 |
自动装配示例
使用注解方式实现自动装配, 首先需要对Bean的类标注@Component
或则类似注解来指示Spring IoC这是一个可以由Spring容器管理的Bean的类. 再在需要注释的构造函数或者字段或则setter方法上标注@Autowired
注解来实现自动注入.
简单示例
@Component
public class Keyboard {
private String name;
public Keyboard() { }
public Keyboard(String name) {
this.name = name;
}
@Override
public String toString() {
return "Keyboard{" +
"name='" + name + '\'' +
'}';
}
}
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
public class DIDemo {
public static void main(String[] args) {
String scanPackages = "lab.anoper.ioc.di.computer.component";
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
Computer computer = context.getBean("computer",
lab.anoper.ioc.di.computer.component.Computer.class);
System.out.println(computer);
}
}
输出结果:
Computer{, keyboard=Keyboard{name='null'}}
多个同类型报错示例
java代码:
@Configuration
public class ComputerConfig {
@Bean
public Keyboard keyboard1() {
return new Keyboard("keyboard1");
}
@Bean
public Keyboard keyboard2() {
return new Keyboard("keyboard2");
}
}
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
public class Keyboard {
private String name;
public Keyboard() { }
public Keyboard(String name) {
this.name = name;
}
@Override
public String toString() {
return "Keyboard{" +
"name='" + name + '\'' +
'}';
}
}
public class DIDemo {
public static void main(String[] args) {
String scanPackages = "lab.anoper.ioc.di.computer";
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
Computer computer = context.getBean("computer",
lab.anoper.ioc.di.computer.component.Computer.class);
System.out.println(computer);
}
}
输出结果:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2
说明构造函数自动装配模式下, 当有超过一个同类型bean时候, 会报出致命错误.
- 解决方案1: 修改代码, 使用
@Primary
注解标注一个主要的bean, 则可以成功.
@Configuration
public class ComputerConfig {
@Bean
@Primary
public Keyboard keyboard1() {
return new Keyboard("keyboard1");
}
@Bean
public Keyboard keyboard2() {
return new Keyboard("keyboard2");
}
}
- 解决方案2: 使用
@Qualifier
注解明确需要装配的bean的名称.
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(@Qualifier("keyboard2") Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
优缺点
优点:
- 减少了属性配置或者是构造函数配置.
- 在更新代码时候, 更懂更小, 不必更新依赖关系.
缺点:
- 显式的申明总是会覆盖掉自动装配.
- 不如显式装配精确.
- 如果有同一个类型的多个值存在, 可能引发错误.
总结
使用@Autowired
注解可以实现自动注入. 配置在属性字段名上使用setter方法注入, 配置在构造函数上将使用构造函数方式注入. 如果有个同类型的bean则会导致致命注入失败, 可以使用@Prmiary
注解来确定一个主要组件, 或者在注入点使用@Qualifier
来注明使用的bean的名字.