前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Ioc源码分析 之 Bean的加载(七):属性填充

Spring Ioc源码分析 之 Bean的加载(七):属性填充

作者头像
炳臣
发布2019-10-15 10:47:57
8090
发布2019-10-15 10:47:57
举报
文章被收录于专栏:一块自留地一块自留地

在上篇文章中,我们详细分析了doCreateBean()中的4步:单例模式的循环依赖处理,本文接着分析doCreateBean()的第5步“属性填充”,也就是populateBean()方法。

首先回顾下CreateBean的主流程:

  1. 如果是单例模式,从factoryBeanInstanceCache 缓存中获取BeanWrapper 实例对象并删除缓存
  2. 调用 createBeanInstance() 实例化 bean
  3. 后置处理
  4. 单例模式的循环依赖处理
  5. 属性填充
  6. 初始化 bean 实例对象
  7. 依赖检查
  8. 注册bean的销毁方法

本章我们主要分析第5步:

在Spring中属性注入有三种方式:

  • xml配置
  • 注解方式
  • 手动get\set方法

xml方式如<beans>节点中的default-autowire属性

注解方式如:@Value()、@Resource、@Autowire、@Qualifier

本文我们主要分析 注解方式 的属性注入

一、populateBean(beanName, mbd, instanceWrapper)

代码语言:javascript
复制
//AbstractAutowireCapableBeanFactory.java

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	//校验实例
	if (bw == null) {
		if (mbd.hasPropertyValues()) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
		}
		else {
			// Skip property population phase for null instance.
			return;
		}
	}

	// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
	// state of the bean before properties are set. This can be used, for example,
	// to support styles of field injection.

	/*
	 * 在设置属性之前给 InstantiationAwareBeanPostProcessors 最后一次改变 bean 的机会。
	 * 关于这段后置引用,官方的解释是:让用户可以自定义属性注入。比如用户实现一
	 * 个 InstantiationAwareBeanPostProcessor 类型的后置处理器,并通过
	 * postProcessAfterInstantiation 方法向 bean 的成员变量注入自定义的信息。当然,如果无
	 * 特殊需求,直接使用配置中的信息注入即可。另外,Spring 并不建议大家直接实现
	 * InstantiationAwareBeanPostProcessor 接口,如果想实现这种类型的后置处理器,更建议
	 * 通过继承 InstantiationAwareBeanPostProcessorAdapter 抽象类实现自定义后置处理器。
	 */
	boolean continueWithPropertyPopulation = true;

	// bean 不是"合成"的,即未由应用程序本身定义 && 持有 InstantiationAwareBeanPostProcessor
<1>	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		// 遍历所有的 BeanPostProcessors
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// 返回值为是否继续填充 bean
				// postProcessAfterInstantiation:如果应该在 bean上面设置属性则返回 true,否则返回 false
				// 一般情况下,应该是返回true 。
				// 返回 false 的话,将会阻止在此 Bean 实例上调用任何后续的 InstantiationAwareBeanPostProcessor 实例。
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					continueWithPropertyPopulation = false;
					break;
				}
			}
		}
	}

	// 如果后置处理器发出停止填充命令,则终止后续操作
	if (!continueWithPropertyPopulation) {
		return;
	}
	//获取Bean的属性值
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	//处理依赖注入

	//xml方式    即xml中<beans>节点中的default-autowire属性
<2>	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		// 将 PropertyValues 封装成 MutablePropertyValues 对象
		// MutablePropertyValues 允许对属性进行简单的操作,并提供构造函数以支持Map的深度复制和构造。
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

		// Add property values based on autowire by name if applicable.
		//根据Bean名称进行autowiring自动装配处理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}

		// Add property values based on autowire by type if applicable.
		//根据Bean类型进行autowiring自动装配处理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}



	// 是否已经注册了 InstantiationAwareBeanPostProcessors
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	//是否需要依赖检查(xml)
	boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
        //属性注入(注解方式)
	//已经注册IABP && 需要依赖检查
<3>	if (hasInstAwareBpps || needsDepCheck) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		if (hasInstAwareBpps) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 具体处理属性注入(注解方式)!!! 如@Value()、@Resource、@Autowire
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvs == null) {
						return;
					}
				}
			}
		}
		//依赖检查 (xml)
<4>		if (needsDepCheck) {
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
	}

<5>	if (pvs != null) {
		//对属性进行注入 (xml)
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
	}
复制代码

主要分为以下几个步骤:

  • 判断是否有自定义属性注入
  • 属性注入(xml方式)
  • 属性注入(注解方式)
  • 依赖检查(xml方式)
  • 注入属性(xml方式)

1.1、判断是否有自定义属性注入

在上述代码<1>处:

代码语言:javascript
复制
        /*
	 * 在设置属性之前给 InstantiationAwareBeanPostProcessors 最后一次改变 bean 的机会。
	 * 关于这段后置引用,官方的解释是:让用户可以自定义属性注入。比如用户实现一
	 * 个 InstantiationAwareBeanPostProcessor 类型的后置处理器,并通过
	 * postProcessAfterInstantiation 方法向 bean 的成员变量注入自定义的信息。当然,如果无
	 * 特殊需求,直接使用配置中的信息注入即可。另外,Spring 并不建议大家直接实现
	 * InstantiationAwareBeanPostProcessor 接口,如果想实现这种类型的后置处理器,更建议
	 * 通过继承 InstantiationAwareBeanPostProcessorAdapter 抽象类实现自定义后置处理器。
	 */
	 boolean continueWithPropertyPopulation = true;

        // bean 不是"合成"的,即未由应用程序本身定义 && 持有 InstantiationAwareBeanPostProcessor
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		// 遍历所有的 BeanPostProcessors
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// 返回值为是否继续填充 bean
				// postProcessAfterInstantiation:如果应该在 bean上面设置属性则返回 true,否则返回 false
				// 一般情况下,应该是返回true 。
				// 返回 false 的话,将会阻止在此 Bean 实例上调用任何后续的 InstantiationAwareBeanPostProcessor 实例。
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					continueWithPropertyPopulation = false;
					break;
				}
			}
		}
	}

	// 如果后置处理器发出停止填充命令,则终止后续操作
	if (!continueWithPropertyPopulation) {
		return;
	}

这部分逻辑注释上已经写的很清楚了。

1.2、属性注入(xml方式)

代码语言:javascript
复制
//xml方式    即xml中<beans>节点中的default-autowire属性
	if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
		// 将 PropertyValues 封装成 MutablePropertyValues 对象
		// MutablePropertyValues 允许对属性进行简单的操作,并提供构造函数以支持Map的深度复制和构造。
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

		// Add property values based on autowire by name if applicable.
		//根据Bean名称进行autowiring自动装配处理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}

		// Add property values based on autowire by type if applicable.
		//根据Bean类型进行autowiring自动装配处理
		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}

		pvs = newPvs;
	}

这部分代码主要是来处理XML方式的属性注入,例如xml中<beans>节点中的default-autowire属性,因为本次Spring系列主要是分析注解方式的,这里就不详细分析了。感性趣的朋友可以自己趣了解下~

1.2、属性注入(注解方式)
代码语言:javascript
复制
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
	if (hasInstAwareBpps) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			// 处理依赖注入(注解方式) 如@Value()、@Resource、@Autowire
			pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
			if (pvs == null) {
				return;
			}
		}
	}
	}

这段代码就是我们要分析的核心。

首先是判断是否已经注册了InstantiationAwareBeanPostProcessor(实例化Bean的后置处理器),如果注册了,就遍历所有的后置处理器。 我们先来了解下InstantiationAwareBeanPostProcessor的类图结构:

InstantiationAwareBeanPostProcessor是一个关于对象实例化前后以及实例化后设置propertyValues的回调处理器。 它有三个方法:

代码语言:javascript
复制
        //这个方法用来在对象实例化前直接返回一个对象(如代理对象)来代替通过内置的实例化流程创建对象;
        @Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}
	
	//在对象实例化完毕执行populateBean之前 如果返回false则spring不再对对应的bean实例进行自动依赖注入。
	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}
	
	 //这里是在spring处理完默认的成员属性,应用到指定的bean之前进行回调,可以用来检查和修改属性,最终返回的PropertyValues会应用到bean中
        //@Autowired、@Resource、@Value等就是根据这个方法来实现最终注入依赖的属性的。
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}
复制代码

我们主要看第三个方法postProcessPropertyValues(),这个方法就是通过注解进行属性注入的具体实现。

该方法主要有3个实现,分别对应了不同的注解。

  • AutowiredAnnotationBeanPostProcessor 可以处理@Autowire、@Value
  • CommonAnnotationBeanPostProcessor 可以处理@Resource
  • RequiredAnnotationBeanPostProcessor 可以处理@Required
1.2.1、AutowiredAnnotationBeanPostProcessor

是Spring容器专门处理配置了自动依赖注入装配相关注解(@Autowire、@Value以及其他JSR-330注解)的Bean后置处理器。详细说明见Spring注解@Autowired源码分析

1.2.2、CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor是Spring中用于处理JavaEE5中常用注解(主要是EJB相关的注解)和Java6中关于JAX-WS相关的注解,可以处理@PostConstruct、@PreDestroy等Bean生命周期相关事件的注解,该后置处理最核心的是处理@Resource注解,同时还可以处理JAX-WS相关的注解。详细说明见Spring注解@Resource源码分析

总结

到这里就已经完成了注解方式所有属性的注入了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年10月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、populateBean(beanName, mbd, instanceWrapper)
    • 1.1、判断是否有自定义属性注入
      • 1.2、属性注入(xml方式)
        • 1.2、属性注入(注解方式)
        • 1.2.1、AutowiredAnnotationBeanPostProcessor
        • 1.2.2、CommonAnnotationBeanPostProcessor
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档