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

在上篇文章中,我们详细分析了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)

//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>处:

        /*
	 * 在设置属性之前给 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方式)

//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、属性注入(注解方式)

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的回调处理器。 它有三个方法:

        //这个方法用来在对象实例化前直接返回一个对象(如代理对象)来代替通过内置的实例化流程创建对象;
        @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源码分析

总结

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java技术栈

Java RPC 分布式框架性能大比拼,Dubbo排老几?

Dubbo 是开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。

6910
来自专栏孟君的编程札记

建造者模式浅析

建造者模式是一种创建型的模式,其意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

9830
来自专栏程序员的成长之路

30个精简代码的小技巧(第21-30个)

这样在编译运行时就可以把这些内容放入常量池中,避免运行期间计算生成常量的值。另外,将常量的名字进行大写。

8430
来自专栏Java知己

Java13 闪亮来袭,你是否还停留在 Java8

近期 Java 界好消息频传。先是 Java 13 发布,接着 Eclipse 也发布了新版本表示支持新版本的 Java 特性。

20460
来自专栏码匠的流水账

聊聊nacos的NacosDiscoveryAutoConfiguration

本文主要研究一下nacos的NacosDiscoveryAutoConfiguration

7000
来自专栏Java技术栈

推荐 33 个 IDEA 最牛配置,写代码太爽了!

blog.csdn.net/fly910905/article/details/77868300

33360
来自专栏Java技术栈

Spring Boot 中的 Tomcat 是如何启动的?

https://my.oschina.net/luozhou/blog/3088908

9410
来自专栏java大数据

Mybatis中数据库的增删改查和动态Sql

以下例子的配置文件中出现了一些mybatis特有的动态Sql的标签,比如trim,foreach或set标签。动态Sql是为了应对更多的情况。trim标签的功能...

12490
来自专栏Java技术栈

如何写好 Java 代码!

代码中的"坏味道",如"私欲"如"灰尘",每天都在增加,一日不去清除,便会越累越多。如果用功去清除这些"坏味道",不仅能提高自己的编码水平,也能使代码变得"精白...

11330
来自专栏凯哥Java

springboot系列教程导学篇

Spring Boot 虽然凯哥从2015年年初开始就接触了spring boot。但是在之后的公司中都没有使用到,来来回回学了好几次了。正好,公司现在准备使用...

12700

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励