前言
自动装配是Spring满足bean依赖的一种重要方式,它是通过IOC容器在上下文中自动寻找,并自动给bean装配属性的一个过程。
1. 隐式的自动装配bean
在Spring官方文档的描述中,对于装配共有三种方式:
- 在xml中显示的配置 (简单来说就是在.xml中通过property和value进行赋值)
<bean id = "hello" class="com.gs.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
- 在java中通过代码进行显示配置(使用的比较少)
- 隐式的自动配置bean(这里有两种形式,一种是在xml通过byType,byName实现,一种是在java类中通过@Autowired等注解实现)
最后一种最为重要,也较为方便。通过一个具体实例来说明这两种实现形式的用法
1.1 在xml上实现隐式自动装配
[1] 创建实体类(三个实体类,一个人和两只宠物)
最终的环境为:
Cat.java
package com.gs.pojo;
public class Cat {
public void shout(){
System.out.println("miao~");
}
}
Dog.java
package com.gs.pojo;
public class Dog {
public void shout(){
System.out.println("wang~");
}
}
Person.java (一个人拥有一只猫和一条狗)
package com.gs.pojo;
public class Person {
private String name;
private Cat cat;
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
[2] 导入Maven依赖(一个Spring的相关包,一个测试包)
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>
[3] 编写beans.xml 进行实体类的装配(即我们之前用的new实体类)
- 通过ByName进行装配
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.gs.pojo.Cat"/>
<bean id="dog" class="com.gs.pojo.Dog"/>
<!--通过autowired的byName进行名字的查找装配,这时dog和cat已经装配进实体类Person中了-->
<bean id = "person" class="com.gs.pojo.Person" autowire="byName">
<property name="name" value="gs"/>
</bean>
</beans>
- 通过ByType进行自动装配(开头文件与上面一致,下面就不再重复了)
<bean class="com.gs.pojo.Cat"/>
<bean class="com.gs.pojo.Dog"/>
<!--byName: 会自动在容器上下文中查找,和自己对象set方法名字相同的bean id
byTape: 会自动在容器上下文中查找,和自己对象set方法类型相同的class
-->
<bean id = "person" class="com.gs.pojo.Person" autowire="byType">
<property name="name" value="gs"/>
</bean>
两种形式分别进行测试
import com.gs.pojo.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
person.getDog().shout();
person.getCat().shout();
}
}
很明显,我们通过ByType和ByName替代了我们之前使用的property和value(ref)的操作,这里我们通过类型和名字进行了相关实体类的自动装配。
小结:
- 使用byName的时候,需要保证所有的bean的id唯一,并且这个bean id需要和我们自己set对象属性名一致
就如:Person类中的属性名cat和bean中的id值一致。 - 使用byType的时候,需要保证所有的bean的clsaa唯一,并且这个bean class需要和自己set对象属性的类型一致
1.2 使用注解实现自动装配
关于测试环境的搭建和上面一致
区别点:
在使用注解时需要在beans.xml中导入约束 (context约束)
在beans.xml中配置注解的支持
<context:annotation-config/>
所以我们对上面的beans.xml进行修改
(这里我们只进行了实体类的注入,并没有对属性进行装配)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解-->
<context:annotation-config/>
<bean id="cat" class="com.gs.pojo.Cat"/>
<bean id="dog" class="com.gs.pojo.Dog"/>
<bean id = "person" class="com.gs.pojo.Person" />
</beans>
[1] 使用@Autowired对属性进行装配
- @Autowired是按照类型进行匹配的,它可以直接在属性上使用,也可以在set方式上使用
- 使用@Autowired我们可以不编写set方法,但前提是这个自动装配的属性在IOC容器中已经存在了,且符合byType,没有在beans.xml中配置多个相同类型
在Person中使用: (这样就是现了cat和dog两个属性的装配了)
public class Person {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
这个代码的测试和上面的结果一致
[2] 对于在beans.xml中配置了多个相同类型的实体类时,由于@Autowired是根据类型查找,由于类型一致,且有多个,那么它在匹配时会产生混乱,这时候需要结合@Qualifer(value=“xxx”)来指定名字进行相关装配
beans.xml中(这是存在多个cat)
<bean id="cat1" class="com.gs.pojo.Cat"/>
<bean id="cat2" class="com.gs.pojo.Cat"/>
<bean id="dog" class="com.gs.pojo.Dog"/>
<bean id = "person" class="com.gs.pojo.Person" />
装配时
public class Person {
private String name;
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
@Autowired
private Dog dog;
[3] 上面都是通过类型进行装配的,那么什么注解是通过名字进行装配呢?在java注解中@Resource很好的诠释了这一点,这个注解可以说是@Autowired和@Qualifer的结合。
@Resource默认是按照名称进行装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入
beans.xml
<bean id="cat" class="com.gs.pojo.Cat"/>
<bean id="cat2" class="com.gs.pojo.Cat"/>
<bean id="dog" class="com.gs.pojo.Dog"/>
<bean id = "person" class="com.gs.pojo.Person" />
装配:(这时是可以完美匹配的,因为cat在beans.xml中能找到)
public class Person {
private String name;
@Resource
private Cat cat;
@Autowired
private Dog dog;
那我们该一下bean.xml的内容(这时候没有cat这个属性名)
<bean id="cat1" class="com.gs.pojo.Cat"/>
<bean id="cat2" class="com.gs.pojo.Cat"/>
<bean id="dog" class="com.gs.pojo.Dog"/>
<bean id = "person" class="com.gs.pojo.Person" />
我们原来装配的代码就会报错了,为什么呢?
在上面我们说过@Resource默认是按名字匹配的,如果找不到可以按类型匹配,那么我们没有cat这个名字,此时类型又有两个是一致的,那么它的匹配又会出现混乱,这是我们可以通过@Resource(name=“xxx”)来指定装配的名字
public class Person {
private String name;
@Resource(name = "cat1")
private Cat cat;
@Autowired
private Dog dog;
@Resource和@Autowired的异同:
- 都是用来装配的,都可以放在属性字段上
- @Autowired是通过byType方法实现的,而且必须要求这个对象存在
- @Resource默认是通过byName的方式实现的,如果找不到名字,则通过byType来实现,如果两个都找不到就会报错。
- @Autowired是Spring上的注解,@Resource是Java上的注解
一天一句鼓励自己的话,即使再小的帆也能远航 。 -----出自最喜欢的UP主狂神