基于xml与注解方式进行自动装配
自动装配就是Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值,也就是根据指定的装配规则(可以是属性名,也可以是属性类型),Spring会自动将匹配的属性值在IOC容器中进行注入。
1. xml方式
1.1. xml下的自动装配过程
- 通过在配置文件中使用bean标签在对bean注入时,使用标签中的
autowire
属性,可用来完成自动装配,这样就可以完成基于xml方式的自动装配。
* autowire属性值:
* byName:根据属性名称注入,但注入值bean的id需要和类属性名一致
* byType:根据属性类型注入,但不能声明多个同类型注入值bean
1.1.1. 代码测试
- 比如之前讲过的依赖注入中提到,可以使用引用型注入方法,在我们的配置文件中使用
property
标签的ref
属性进行bean引用,或者在property标签中进行bean注入
,而自动装配则使用的是bean标签中的autowired属性
,如下举例
public class Dept {
private String deptName;
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getDeptName() {
return deptName;
}
@Override
public String toString() {
return "Dept{" +
"deptName='" + deptName + '\'' +
'}';
}
}
##########################################
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public Dept getDept() {
return dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
public void test(){
System.out.println(dept);
}
}
##################################3333
Spring配置文件
<bean id="emp" class="com.spring5.autowire.Emp" autowire="byName"></bean>
<bean id="dept" class="com.spring5.autowire.Dept">
<property name="deptName" value="实验部"/>
</bean>
##################################3333
测试代码
@Test
public void testAutoWire(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean8.xml");
com.spring5.autowire.Emp emp = context.getBean("emp", com.spring5.autowire.Emp.class);
System.out.println(emp);
}
运行结果:
2. 注解方式
- 使用注解方式进行自动装配主要应用与我们的日常开发学习中,比如在service层调用dao层;controller层调用service层,需要在一个组件中去调用另一个组件。
2.1. @Autowired自动注入
@Autowired 可以标注在方法和构造器,参数,属性位置,但都是从IOC容器中获取参数组件的值:
* 方法上:
Spring 容器创建当前对象时,就会调用被标注的方法完成赋值
方法所需的参数若是自定义类型,则从IOC容器中获取
使用@Bean+方法参数,参数从容器中获取,默认不写@Autowired
* 构造器:
默认加在IOC容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
构造器要用的组件,也都是从容器中获取,(当前类(组件)若只有一个有参构造器,@Autowired可省略)
* 参数:
同从容器中获取
2.1.1. 代码测试
相关代码
//@Component
public class Car {
public Car() {
System.out.println("Car constructor");
}
}
#########################
@Component
public class Boss {
private Car car;
public Boss(Car car) {
System.out.println("Boss args contrastor");
this.car = car;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Boss{" +
"car=" + car +
'}';
}
}
2.1.1. 标注在方法上测试
@Autowired
public void setCar(Car car) {
this.car = car;
}
- 当我们不在IOC容器中注册Car组件时获取Boss组件,发生报错
- 在IOC容器中注册Car组件后获取Boss组件
2.1.1. 标注在构造器上测试
@Autowired
public Boss(Car car) {
System.out.println("Boss args contrastor");
this.car = car;
}
public Boss(String name, Car car) {
this.name = name;
this.car = car;
}
- 当存在两个有参构造器时,必须选择一个构造器标识@Autowired注解,否则会报错
测试结果:
2.1.1. 标注在参数上测试
public void setCar(@Autowired Car car) {
this.car = car;
}
测试结果:
2.2. 如何使用@Autowired注解
1。一个组件需要调用另外一个组件,只需要在被调用的组件上标注@Autowired即可;
默认优先按照类型去容器中找对应的组件,找到就赋值;
2。如果找到多个相同类型的组件,再将属性名作为组件id去容器中查找,也就是在容器中找到了多个类型相同的组件,但组件id肯定不会相同,这个时候就看添加@Autowired注解的属性名是什么 ,优先选择组件ID和属性名一致的组件进行注入(也可以通过修改属性名来选择组件)
3。@Qualifier :指定需要装配的组件的id,而不是使用属性名;就是容器中有多个同类型组件,但是会默认优先选择组件ID同属性名的组件,而此时我们又只想要另一个与属性名不同名的组件,此时,就可以使用@Qualifier注解进行组件指定
4。自动装配默认一定要先对属性进行赋值,可在容器中找到该组件,否则会报错 ,也就是说我们在进行自动装配时,一定要先将组件注入到IOC容器中,使用@Autowired就相当于对属性赋值,而这个赋值就是是在容器中找到对应的组件,将该组件与属性进行绑定,完成属性赋值操作;如果说我们没有在IOC容器中进行组件注册,就需要使用@Autowired(required = false)进行设置,required默认true,就是必须要在容器中注册之后才能进行赋值操作,设置为false之后就是能在容器中找到就进行装配,找不到就不管了,组件赋值为null
5。@Primary:让Spring在进行自动装配时,默认首选注册的bean,也就是容器中有多个同类型组件时,默认优先选择标识@Primary注解的组件,所以该注解与@Qualifier相矛盾,前者是默认优先选择,后者是明确指定,如果同时添加@Qualifier注解,则就继续装配指定的组件了
(当我们按类型在容器中获取某单个bean实例时,如果出现多个同类型bean时会报错,但如果某个组件使用@Primary注解时就会选择@primary注解的bean,如果需要其他组件,此时就需要按照组件名字去容器中获取)
2.2.1. 代码测试
2.2.1.1 一个组件需要调用另外一个组件
controller调用service,service调用dao
@Controller
public class BookController {
@Autowired
private BookService bookService;
public BookService getBookService() {
return bookService;
}
}
#####################################
测试代码
@Test
public void test3() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyconfigOfAutoWired.class);
BookController bean = context.getBean(BookController.class);
System.out.println(bean.getBookService());
}
运行结果:
2.2.1.2 如果找到多个相同类型的组件,再将属性名作为组件id去容器中查找
###################################
两个dao组件
@Repository
public class BookDao {
private String label = "1"; // 识别组件标签
}
@Bean("bookDao2")
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLabel("2");
return bookDao;
}
###################################
service
@Service
public class BookService {
@Autowired
private BookDao bookDao;
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
#####################################
测试代码
@Test
public void test4() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyconfigOfAutoWired.class);
BookService bean = context.getBean(BookService.class);
System.out.println(bean);
}
运行结果:
2.2.1.3. 指定需要装配的组件的id
@Service
public class BookService {
@Autowired
@Qualifier("bookDao2")
private BookDao bookDao;
}
其余代码同上2.1.1.2 ,只需添加 @Qualifier("bookDao2")
运行结果:
2.2.1.4 required=false
- 目前我们IOC容器中注册的组件如下
- 当我们去使用@Autowired去为BookService中的bookDao属性来赋值时
@Service
public class BookService {
@Autowired
private BookDao bookDao;
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
,就会报错如下
- 代码测试required=false
@Service
public class BookService {
@Autowired(required = false)
private BookDao bookDao;
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
2.2.1.5. @Primary
@Bean("bookDao2")
@Primary
public BookDao bookDao(){
BookDao bookDao = new BookDao();
bookDao.setLabel("2");
return bookDao;
}
********************************************
@Service
public class BookService {
@Autowired
// @Qualifier("bookDao")
private BookDao bookDao;
@Override
public String toString() {
return "BookService{" +
"bookDao=" + bookDao +
'}';
}
}
################################################
测试代码
@Test
public void test4() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyconfigOfAutoWired.class);
BookService bean = context.getBean(BookService.class);
System.out.println(bean);
}
运行结果:
去掉@Qualifier(“bookDao”)注释之后运行结果:
2.3. 了解内容
2.3.1 java规范的JSR250注解
- Spring支持JSR250的@Resource(jdk11后不支持)和@Inject
@Resource
:
可以和@Autowired一样实现自动装配功能,
默认按照组件名称进行装配,
但不支持@Primary和@Autowired(required=false) 功能
@Inject
:
功能等同@Autowired,
但无@Autowired(required=false) 功能