Spring 中自动装配 autowire 机制是指,由 Spring Ioc 容器负责把所需要的 bean,自动查找和赋值到当前在创建 bean 的属性中,无需手动设置 bean 的属性。
1、基于 xml 配置 bean 的装配方式:
no:默认的方式是不进行自动装配的,需要通过手工设置 ref 属性来进行装配 bean。
byName:通过 bean 的名称进行自动装配,如果一个 bean 的 property 与另一 bean 的 name 相同,就进行自动装配。
byType:通过参数的数据类型进行自动装配。
constructor:通过构造函数进行装配,并且构造函数的参数通过 byType 进行装配。
autodetect:自动探测,如果有构造方法,通过 construct 的方式自动装配,否则使用 byType 的方式自动装配。( 已弃用)
方式的定义在 AutowireCapableBeanFactory.AUTOWIRE_NO
AUTOWIRE_BY_NAME
AUTOWIRE_BY_TYPE
AUTOWIRE_CONSTRUCTOR
AUTOWIRE_AUTODETECT
2、基于注解完成 bean 的装配
@Autowired、@Resource、@Inject 都可以实现 bean 的注入
@Autowired 是 Spring 推出的,功能最为强大,可以作用于 构造方法、setter 方法、参数、成员变量、注解(用于自定义扩展注解)
@Resource 是 JSR-250 的规范推出
@Inject 是 JSR-330 的规范推出
@Value 可以注入配置信息
@Autowired、@Inject、@Value 的解析工作是在 AutowiredAnnotationBeanPostProcessor 内,如何源码 1
@Resource 的解析工作是在 CommonAnnotationBeanPostProcessor 内,如何源码 2
源码 1、
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
源码 2、
static {
...
resourceAnnotationTypes.add(Resource.class);
...
}
基于 xml 的代码示例
1、no 方式
spring 配置文件,使用 ref 参数注入 bean,必须要有对象的 setter 方法,这里即 Person 的 setFr 方法。
没有 <property name="fr" ref="fr"></property> 因没有注入 fr 属性,会报空指针错误。
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="person" class="constxiong.interview.assemble.Person" autowire="no">
<property name="fr" ref="fr"></property>
</bean>
<bean id="fr" class="constxiong.interview.assemble.FishingRod"></bean>
</beans>
鱼竿 bean
package constxiong.interview.assemble;
/**
* 鱼竿
* @author ConstXiong
* @date 2019-07-17 09:53:15
*/
public class FishingRod {
/**
* 被使用
*/
public void used() {
System.out.println("钓鱼...");
}
}
人 bean
package constxiong.interview.assemble;
/**
* 人
* @author ConstXiong
* @date 2019-07-17 09:54:56
*/
public class Person {
private FishingRod fr;
/**
* 钓鱼
*/
public void fish() {
fr.used();
}
public void setFr(FishingRod fr) {
this.fr = fr;
}
}
测试代码
package constxiong.interview.assemble;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AssembleTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring_assemble.xml");
Person person = (Person)context.getBean("person");
person.fish();
}
}
2、byName 也是需要相应的 setter 方法才能注入
修改 spring 配置文件 autowire="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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="person" class="constxiong.interview.assemble.Person" autowire="byName"></bean>
<bean id="fr" class="constxiong.interview.assemble.FishingRod"></bean>
</beans>
3、byType 也是需要相应的 setter 方法才能注入
修改 spring 配置文件 autowire="byType"
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="person" class="constxiong.interview.assemble.Person" autowire="byType"></bean>
<bean id="fr" class="constxiong.interview.assemble.FishingRod"></bean>
</beans>
其他不变
4、constructor 无需 setter 方法,需要通过 构造方法注入 bean
修改 spring 配置文件 autowire="byType"
Person 类去除 setFr 方法,添加构造方法设置 fr 属性
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="person" class="constxiong.interview.assemble.Person" autowire="constructor"></bean>
<bean id="fr" class="constxiong.interview.assemble.FishingRod"></bean>
</beans>
package constxiong.interview.assemble;
/**
* 人
* @author ConstXiong
* @date 2019-07-17 09:54:56
*/
public class Person {
private FishingRod fr;
public Person(FishingRod fr) {
this.fr = fr;
}
/**
* 钓鱼
*/
public void fish() {
fr.used();
}
}
1、2、3、4 的测试结果一致,打印
钓鱼...