Spring中的依赖注入分两种:一种是手动依赖注入,另一种是自动依赖注入。
手动注入
在XML中定义Bean时,就是手动依赖注入,因为是程序员手动给某个属性指定了值。
手动注入底层也分两种:一种是set方法注入,另一种是构造方法注入。
set方法注入
<bean name="userService" class="com.spring.service.UserService">
<property name="orderService" ref="orderService"/>
</bean>
构造方法注入
<bean name="userService" class="com.spring.service.UserService">
<constructor-arg index="0" ref="orderService"/>
</bean>
手动注入会在解析Bean对象生成对应的BeanDefinition时将依赖关系记录在PropertyValues属性中(PropertyValues本质上就是一个Map)。
XML自动依赖注入
在XML中,我们可以在定义一个Bean时去指定这个Bean的自动注入模式:
- byType
- byName
- constructor
- default
- no
例如:
<bean id="userService" class="com.spring.service.UserService" autowire="byType"/>
这么写,表示Spring会自动的给userService中所有的属性自动赋值(需要这个属性有对应的set方法)。
今天只分析set方法注入的byName和byName这两种自动装配模式。
在创建Bean的过程中,在填充属性时,会进行byName和byName两种自动装配模式的依赖注入。
// 属性填充
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 省略部分代码...
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// MutablePropertyValues是PropertyValues的具体实现类
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 通过byName的自动填充属性
// 1. 找到所有set方法所对应的XXX部分的名字
// 2. 根据XXX部分的名字去获取bean
autowireByName(beanName, mbd, bw, newPvs);
}
// 拿到set方法参数的类型去容器中查找Bean对象来进行依赖注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 通过byType的自动填充属性:
// 1. 获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean
// 2. 如果找到多个,会报错。
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 省略部分代码...
if (pvs != null) {
// 给属性赋值
// 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
PropertyDescriptor:属性描述器
在依赖注入前,spring会解析Bean对象中 public 修饰的 get 和 set 方法,封装成对应的PropertyDescriptor对象,PropertyDescriptor中有几个属性:
private String name;
private final MethodRef readMethodRef = new MethodRef();
private String readMethodName;
private final MethodRef writeMethodRef = new MethodRef();
private String writeMethodName;
private Reference<? extends Class<?>> propertyTypeRef;
- name:这个name并不是方法的名字,而是拿方法名字进过处理后的名字。
- 如果方法名以 get 开头,比如 getOrderService,那么 name = orderService
- 如果方法名以 is 开头,比如 isOrderService,那么 name = orderService
- 如果方法名以 set 开头,比如 setOrderService,那么 name = orderService
- readMethodRef:表示get方法的Method对象的引用
- readMethodName:表示get方法的名字
- writeMethodRef:表示set方法的Method对象的引用
- writeMethodName:表示set方法的名字
- propertyTypeRef:如果有get方法那么对应的就是返回值的类型,如果是set方法那么对应的就是set方法中唯一参数的类型。
get方法的定义:没有方法参数,并且方法名字以 get 开头或者以 is 开头并且方法的返回类型为boolean。
set方法的定义:方法参数个数为1个,并且方法名字以 set 开头并且方法返回类型为 void。
在autowireByName或autowireByName之前,会先通过unsatisfiedNonSimpleProperties()方法解析出需要进行依赖注入的属性名,也就是Bean中的set方法的name(PropertyDescriptor中的name属性)。
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
PropertyValues pvs = mbd.getPropertyValues();
// 拿到当前Bean对象的所有属性描述器
// 1.先从缓存中拿
// 2.若缓存中没有,则会解析Bean的每个方法,得到对应的PropertyDescriptor对象
// 3.将解析得到的PropertyDescriptor缓存起来
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
// 遍历属性描述器
for (PropertyDescriptor pd : pds) {
// 条件1:有set方法
// 条件2:未被排除在依赖检查项之外
// 条件3:没有通过BeanDefinition来指定该属性的注入值,即程序员没有自己为该属性指定注入对象(如果程序员自己指定了,则以程序员自己指定的为主)
// 条件4:不是简单类型或简单类型的数组
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
// 以上4个条件都满足,说明该属性需要注入,加入到结果集
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
public static boolean isSimpleProperty(Class<?> type) {
// 是否为简单类型或简单类型数组
return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}
// 判断type是否为简单类型
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
// 原生类型或其包装类型
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
// 字符串
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
autowireByName
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 解析Bean中需要进行依赖注入的所有属性名
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历属性名
for (String propertyName : propertyNames) {
// 容器中是否有propertyName对应的Bean对象
// 先判断单例池有没有propertyName对应的Bean对象
// 若单例池中没有,则再判断有没有propertyName对应的BeanDefinition
// 若本容器中没有,则再判断父容器
if (containsBean(propertyName)) {
// 根据名称到容器中找到对应的Bean对象
Object bean = getBean(propertyName);
// 将找到的结果添加到pvs中
pvs.add(propertyName, bean);
// 注册bean之间的依赖关系:
// 1.beanName对应的Bean依赖了propertyName对应的Bean;
// 2.propertyName对应的Bean被beanName对应的Bean依赖了
registerDependentBean(propertyName, beanName);
}
}
}
autowireByType
protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取BeanFactory中自定义类型转换器
TypeConverter converter = getCustomTypeConverter();
// 如果没有配置自定义类型转换器就使用BeanWrapper作为类型转换器
// BeanWrapper继承了TypeConverter
if (converter == null) {
converter = bw;
}
// 定义一个集合用于存放所有候选Bean的Name
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 解析Bean中需要进行依赖注入的所有属性名
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
// 遍历propertyNames
for (String propertyName : propertyNames) {
// 拿到propertyName对应的PropertyDescriptor
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 不能是Object类型,要是Object的子类型
if (Object.class != pd.getPropertyType()) {
// 拿到set方法的参数
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// 当前Bean是否实现了PriorityOrdered接口
// eager表示立即初始化,表示在根据类型查找Bean时,允不允许Bean的创建
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 获取到set方法中的唯一参数的参数类型,并且根据该类型去容器中获取bean
// 如果找到多个,会报错。
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 将找到的结果添加到pvs中
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 注册bean之间的依赖关系:
// 1.beanName对应的Bean依赖了autowiredBeanName对应的Bean;
// 2.autowiredBeanName对应的Bean被beanName对应的Bean依赖了
registerDependentBean(autowiredBeanName, beanName);
}
// 清空autowiredBeanNames
autowiredBeanNames.clear();
}
}
}
从本质上来将,xml的自动依赖注入就是找到Bean对象中的所有符合特定条件的set方法,然后通过byName或者byType从容器中找到set方法需要的参数对象,然后调用set方法的过程。
注意:在set方法内部给属性赋值操作需要程序员自己实现,spring只管调用set方法。