初识Spring源码 -- 属性填充populateBean | 静态属性注入

Posted 做猪呢,最重要的是开森啦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初识Spring源码 -- 属性填充populateBean | 静态属性注入相关的知识,希望对你有一定的参考价值。

0. 举个栗子:

@Component
public class SetterBean {
    @Autowired
    private BeanService beanService;

    @Autowired
    public void setBean() {
        BeanServiceImpl bean = new BeanServiceImpl();
        bean.setName("WTF");
        beanService = bean;
    }
}

@Configuration
public class ConfigurationBean {

    @Bean
    public BeanService beanService() {
        BeanServiceImpl beanService = new BeanServiceImpl();
        beanService.setName("zhangsan");
        return beanService;
    }
}

2. populateBean:

主要源码入口:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

至此,doCreateBean经历以下步骤:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	... ... ...
	// 这块是提前暴露bean,引入三级缓存,解决循环依赖的,这里不做叙述
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		// 属性填充方法populateBean,进行依赖注入等
		populateBean(beanName, mbd, instanceWrapper);
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	... ... ...
}

 以下是属性注入方法populateBean整个方法的概览,下文会逐步介绍重点代码。

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// 这块主要是成立bw == null的异常情况的,感觉没什么用,封装的实例bw不太会为null
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				return;
			}
		}

		// mbd.isSynthetic()默认是false,也不懂什么情况是true,不必理会
		// 同时有实现InstantiationAwareBeanPostProcessor接口的Bean,则继续往下,正常这个条件都是成立的
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 返回false,这个属性就不继续注入,2.1中会说明一下这里
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						return;
					}
				}
			}
		}

		// 暂时不懂什么情况hasPropertyValues有值,难道是xml配置的时候的?
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

		// 采用注解的时候resolvedAutowireMode=0
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		// 这里是针对xml配置的bean,下文2.2会说明
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}

		// 是否有实现InstantiationAwareBeanPostProcessors的bean,到这都是会有的
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		// 是否需要依赖检查,默认false
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					// 这个是重点,postProcessProperties在这进行属性的注入,
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						// 兼容老版本的注入
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			// 依赖检查,对应depends-on属性
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
			// 将所有PropertyValues中的属性填充到bean中
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}
 2.1. postProcessAfterInstantiation:

 这块代码是作为扩展用的,比如有一个实现InstantiationAwareBeanPostProcessor接口的bean,重写方法
·
 在实例化SetterBean后,在属性注入之前给个机会修改bean或者放弃属性注入
·
 比如此处不进行属性beanService注入,返回false;此时SetterBean对象内部属性全为空
·
 除非扩展,不然正常都返回true,像AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor

@Component
public class BeanInstantiaitionAwareImpl implements InstantiationAwareBeanPostProcessor {
 
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if(beanName.equals("setterBean"){
            SetterBean setterBean = (SetterBean) bean;
            setterBean.setXXX("XXX");
            return false;
        }
        //默认返回true,什么也不做,继续下一步 初始化
        return true;
    }
 2.1. resolvedAutowireMode:

 这一块对resolvedAutowireMode判断逻辑代码,是针对xml配置的,可参考链接

在这里插入图片描述

 2.3. postProcessProperties:

 这个是重点,对于@Autowired注入,此处调用的是AutowiredAnnotationBeanPostProcessor这个后置处理器的方法
·
 findAutowiringMetadata方法中,会从缓存中获取到InjectionMetadata,可见链接
·
 再根据属性方法元数据metadata,进行注入

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// 根据属性方法元数据metadata,进行注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}
 2.4. metadata.inject:

 属性元数据封装到AutowiredFieldElement,方法元数据封装到AutowiredMethodElement,最后都封装到InjectionMetadata
`
 二者都是AutowiredAnnotationBeanPostProcessor的内部类,继承InjectionMetadata.InjectedElement

在这里插入图片描述

 循环遍历属性、方法元数据进行注入;封装的对象都是继承InjectedElement的
·
 会先进行属性注入,再进行方法注入,所以属性注入会存在被覆盖的可能,本栗子中,最后注入的beanService的name为WTF
·
 根据这个特性,可以对static修饰的对象,进行方法注入,达到属性注入的效果

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		// 遍历属性/方法元数据
		for (InjectedElement element : elementsToIterate) {
			if (logger.isTraceEnabled()) {
				logger.trace("Processing injected element of bean '" + beanName + "': " + element);
			}
			// 进行注入
			element.inject(target, beanName, pvs);
		}
	}
}
 2.5. element.inject :

 resolveDependency方法来获取依赖的属性bean,这里的详细细节后面再介绍。

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// 就是类属性,反射中的field
	Field field = (Field) this.member;
	Object value;
	if (this.cached) {
		// 有缓存就通过缓存获取注入的属性bean
		value = resolvedCachedArgument(beanName, this.cachedFieldValue);
	}
	else {
		// 构建DependencyDescriptor,required除非显示指定非必须@Autowired(required = false),默认是true
		DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
		desc.setContainingClass(bean.getClass());
		Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
		Assert.state(beanFactory != null, "No BeanFactory available");
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		try {
			// 这是重点,通过resolveDependency来解析出依赖的属性bean对象
			value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
		}
		catch (BeansException ex) {
			throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
		}
		synchronized (this) {
			// 这里是添加缓存的一些逻辑
			if (!this.cached) {
				if (value != null || this.required) {
					this.cachedFieldValue = desc;
					registerDependentBeans(beanName, autowiredBeanNames);
					if (autowiredBeanNames.size() == 1) {
						String autowiredBeanName = autowiredBeanNames.iterator().next();
						if (beanFactory.containsBean(autowiredBeanName) &&
								beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
							this.cachedFieldValue = new ShortcutDependencyDescriptor(
									desc, autowiredBeanName, field.getType());
						}
					}
				}
				else {
					this.cachedFieldValue = null;
				}
				this.cached = true;
			}
		}
	}
	if (value != null) {
		// value就是依赖的属性bean,通过反射修改bean,实现属性注入
		ReflectionUtils.makeAccessible(field);
		field.set(bean, value);
	}
}
 2.6. 小结:

 通过postProcessAfterInstantiation方法,给后置处理器个机会在属性注入之前修改bean或者放弃属性注入,扩展用的
·
 接下来会针对xml配置的bean进行byType / byName处理,注解的bean是不处理的
·
 通过postProcessProperties方法进行属性注入

  • 从预解析的缓存中获取封装了属性、方法元数据的对象InjectionMetadata
  • 循环遍历各元数据,进行注入;先进行属性,再进行方法注入,属性注入会存在被覆盖的可能
  • 通过resolveDependency来解析出依赖的属性bean对象
  • 最后通过反射修改bean,实现属性注入

【参考】:
  你所不知道的Spring的@Autowired实现细节
  Spring源码分析衍生篇五:AutowiredAnnotationBeanPostProcessor

以上是关于初识Spring源码 -- 属性填充populateBean | 静态属性注入的主要内容,如果未能解决你的问题,请参考以下文章

Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

初识Spring源码 -- applyMergedBeanDefinitionPostProcessors

初识Spring源码 -- applyMergedBeanDefinitionPostProcessors

初识Spring源码 -- applyMergedBeanDefinitionPostProcessors

ASP.NET / 模型 - 防止模型预填充表单输入字段

初识Spring源码 -- initializeBean | @PostConstruct | afterPropertiesSet | @Resource