Spring源码剖析之xml自动依赖注入

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的自动注入模式:

  1. byType
  2. byName
  3. constructor
  4. default
  5. 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方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值