spring源码对属性赋值 populateBean(注解)

前篇文章传送门
上篇咱们了解了@Autowired、@Value和@Resource、@PostConstruct、@PreDestroy注解的解析,既然解析了,肯定是要使用,那么接下来咱们看看spring是怎么处理的
了解源码之前,咱们先想几个问题

  1. @Autowired、@Value是在什么时机进行赋值的(postProcessProperties)
  2. @Resource是在什么时机进行赋值的(postProcessProperties)
  3. @PostConstruct、@PreDestroy是在什么时候执行的(BPP.postProcessBeforeInitialization)
  4. 咱们平常开发过程是如何给属性赋值的呢?(构造、set方法、Field.set)
  5. Spring是怎么获取Properties的

那spring是如何做的呢?属性有哪些类型呢?
咱们继续看看spring源码中是如何进行赋值的

源码

AbstractAutowireCapableBeanFactory.populateBean 从bean定义信息中给bean赋值
前面咱们了解过了,所有的xml,注解等都会被解析成beanDefinition,bean定义信息装载了bean所需要的各种信息,但是注解处理的过程有些不一样,接下来咱们看下注解是如何给属性赋值的

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 {
			return;
		}
	}
	// 给 InstantiationAwareBeanPostProcessors 一个机会来修改bean信息,返回false即可结束下面的流程
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}
	}
	// 取出所有的属性值
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	// 可以在xml中指定属性autowire="byName"
	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;
	}
	// 这里为true
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		// 如果不是xml配置
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// CommonAnnotationBeanPostProcessor.postProcessProperties
				// AutowiredAnnotationBeanPostProcessor.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);
		}
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
	// 填充xml中的属性
	if (pvs != null) {
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}
CommonAnnotationBeanPostProcessor.postProcessProperties 给@Resource注解赋值
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// 这里上篇简单的看过了,就是获取注解信息,如果有重复的配置,删除外部的,沿用注解的,类似合并bean的定义信息
	// 返回封装后的元素信息
	InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
	try {
		// 执行注入
		metadata.inject(bean, beanName, pvs);
	}catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
	}
	// 这里在获取元素据的时候有可能会删除掉一部分属性配置
	return pvs;
}
InjectionMetadata.inject 注解注入

在这里插入图片描述

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) {
			element.inject(target, beanName, pvs);
		}
	}
}
InjectedElement.inject 指定注解注入注入

不管是使用属性的方式,还是使用set方法的方式赋值,都需要获取目标对象(需要注入的值)

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {
	// 如果是字段的话,直接使用反射的set方法赋值
	if (this.isField) {
		Field field = (Field) this.member;
		ReflectionUtils.makeAccessible(field);
		// 获取完对象后,直接给属性赋值
		field.set(target, getResourceToInject(target, requestingBeanName));
	}else {
		if (checkPropertySkipping(pvs)) {
			return;
		}
		try {
			// 如果是set方法添加了注解,那么调用对应的set方法
			Method method = (Method) this.member;
			ReflectionUtils.makeAccessible(method);
			// 获取完对象后,直接给属性赋值
			method.invoke(target, getResourceToInject(target, requestingBeanName));
		}catch (InvocationTargetException ex) {
			throw ex.getTargetException();
		}
	}
}
InjectedElement.getResourceToInject 获取对象
// 如果需要代理那么需要返回代理对象,如果不需要代理,那么直接通过BeanFactory进行获取
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :getResource(this, requestingBeanName));
// 从这里可以看出,这是一个大的递归过程,getBean,doGetBean,createBean,doCreateBean...
resource = factory.getBean(name, element.lookupType);
AutowiredAnnotationBeanPostProcessor.postProcessProperties 给@Autowired、@Value注解赋值

@Autowired和@Resource很类似,@Value就是解析表达式,然后去掉${},再去配置文件中获取,拿到值直接设置

// 还是熟悉的配方
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		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;
}
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) {
			element.inject(target, beanName, pvs);
		}
	}
}
AutowiredFieldElement.inject 执行注入
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Field field = (Field) this.member;
	Object value;
	// 如果有解析过,直接获取
	if (this.cached) {
		try {
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}catch (NoSuchBeanDefinitionException ex) {
			value = resolveFieldValue(field, bean, beanName);
		}
	}else {
		// 从工厂中获取
		value = resolveFieldValue(field, bean, beanName);
	}
	if (value != null) {
		ReflectionUtils.makeAccessible(field);
		// 反射赋值
		field.set(bean, value);
	}
}
AutowiredFieldElement.resolveFieldValue 获取对应注入的值

其实这里也很简单,就是去spring容器中获取对应的值。但是需要注意下,如果注入的是spring中的bean对象,那么就会直接走spring的获取流程,如果是@Value注解呢

咱们先来想几个问题

  1. spring中有哪些环境对象
  2. 获取spring中的配置流程是什么
spring中有哪些环境对象?

spring内容包含三部分

  1. 系统环境:如java环境配置 --systemEnvironment
  2. 系统配置:电脑系统名称os.name --systemProperties
  3. 本地配置:本地配置,如配置的配置文件 --localProperties

在这里插入图片描述

/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
获取spring中的配置流程是什么

spring内容包含三部分,从下图可以看出,spring在获取配置的时候,先去environmentProperties中去获取,系统配置包括两部分,先去系统配置中获取,如果获取不到,再去系统环境中获取,如果再获取不到,去本地配置中获取,不管在哪个环节中获取到了,直接返回。这里可以告诉我们,系统配置的优先级最高,比如咱们在shell脚本中配置了某项,优先级肯定比本地配置文件的要高的原因

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值