Spring Bean生命周期之属性赋值阶段详解
作者:码农的进阶之路 发布时间:2022-09-28 04:34:11
前言
上节在谈论Bean的实例化过程时,在说明实例化后阶段时只是粗略地看了一下populateBean
,并未展开分析。本节接着populateBean
开始分析对象赋值阶段的事情。
populateBean其实主要做了以下几件事:
Bean实例化后回调,来决定是否进行属性赋值 (上节分析过了)
对属性进行自动装配
InstantiationAwareBeanPostProcessor
属性赋值前回调属性的真正赋值
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//省略无关代码
// 1、 Bean实例化后回调,来决定是否进行属性赋值
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);
//2、对属性进行自动装配
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
//3、InstantiationAwareBeanPostProcessor属性赋值前回调
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
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 (pvs != null) {
//属性的赋值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
属性自动装配
PropertyValues 对bd中属性的封装,可以理解为bd中属性键值均由其保存,其常用实现类为MutablePropertyValues,在BeanDefinition的概述及使用 有介绍其使用,可点击查看
//这里的bd是已经执行过合并BeanDefinition操作了
//如果bd存在属性 则获取
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
//获取bd的自动注入模式
//注入模式有四种:
//1.构造函数注入 2、按照名称注入 3、按照类型注入 4、不注入(默认,依然可能会被注解驱动注入)
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
//如果是按名称注入或类型注入时
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
//按名称注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
//按类型注入,基本上这种比较常用
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
下面我们分别来大致看下autowireByName
及autowireByType
熟悉下实现原理
autowireByName
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//获取属性名称
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历属性名称
for (String propertyName : propertyNames) {
//如果属性名称已在beanDefinitionMap中,说明其是bd 并已被注册待IoC容器
if (containsBean(propertyName)) {
//根据名称获取其bean对象
Object bean = getBean(propertyName);
//以键值方法赋值到pvs
pvs.add(propertyName, bean);
// 这里是维护dependentBeanMap、dependenciesForBeanMap两个集合,
// 这里不再展开 在说到LifecycleProcessor时再展开
registerDependentBean(propertyName, beanName);
//省略日志输出
}
else {
//省略日志输出
}
}
}
autowireByType
按类型注入稍显复杂些,但流程上与按名称注入类似
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//类型转换器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
//依然是获取属性名称
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历属性名称
for (String propertyName : propertyNames) {
try {
//获取属性描述对象
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
//不对Object类型做注入,因此这里判断条件如下
if (Object.class != pd.getPropertyType()) {
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//解析依赖
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
//以键值方法赋值到pvs
pvs.add(propertyName, autowiredArgument);
}
for (String autowiredBeanName : autowiredBeanNames) {
// 这里是维护dependentBeanMap、dependenciesForBeanMap两个集合,
// 这里不再展开 在说到LifecycleProcessor时再展开
registerDependentBean(autowiredBeanName, beanName);
//省略日志输出
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
//省略异常信息
}
}
接下来我们进入到resolveDependency
,大致分析下解析依赖的主要流程
DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
//如果依赖类型是Optional
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
//如果依赖类型是ObjectFactory或ObjectProvider
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
//如果依赖类型是Inject
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//实际执行解析依赖的逻辑代码
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
//获取依赖类型
Class<?> type = descriptor.getDependencyType();
//获取依赖类型的默认值,如@Value注解 可提供默认值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
//如果默认值是String类型
if (value instanceof String) {
//从配置文件中解析出指定key的数据
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
//类型转换器 用于转换类型,如配置文件中声明的是字符串类型的数字,而java中使用Integer接收,则类型转换器就派上用场了
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
//解析出类型是Stream、Map、数组、Collection等集合类型的依赖。解析的思路很类似 即去IoC容器中 查找集合类实际泛型对应的Bean
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//这里主要是查找单实例Bean的,如果某个类型的Bean有多个,这里会被全部查找出来,因此使用Map接收
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
//如果查找出的Bean有多个,
if (matchingBeans.size() > 1) {
//找出标注了@Primary的那个Bean名称,作为查找出的Bean
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
//如果没有@Primary注解标注,那么抛出NoUniqueBeanDefinitionException
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
//如果查找出的Bean只有1个 那么说明找到了。
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
可以看出resolveDependency
方法还是很强大的,无论是单一类型对象还是集合类型对象,无论是Optional类型还是延迟加载ObjectFactory类型 其均可以解析出来。
属性赋值前回调
//boolean值 判断有没有InstantiationAwareBeanPostProcessor存在
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 这是 是否依赖检查的标记 不是我们此次的重点
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
//IoC容器中如果存在InstantiationAwareBeanPostProcessor
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//遍历BeanPostProcessor,找到InstantiationAwareBeanPostProcessor类型
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//postProcessProperties、postProcessPropertyValues两个方法含义类似。如果postProcessProperties未被重写 则执行postProcessPropertyValues方法
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;
}
}
}
这里针对一个小案例说明下postProcessPropertyValues
和postProcessProperties
的使用
需求:将注入的user对象中name属性由wojiushiwo修改为abc
实体对象User
@Data
@ToString
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
public class MyInstantiationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if(ObjectUtils.nullSafeEquals("user",beanName) && User.class.equals(bean.getClass())){
final MutablePropertyValues propertyValues;
if(pvs instanceof MutablePropertyValues){
propertyValues= (MutablePropertyValues) pvs;
}else{
propertyValues=new MutablePropertyValues();
}
if(propertyValues.contains("name")){
propertyValues.removePropertyValue("name");
propertyValues.addPropertyValue("name","abcd");
}
return propertyValues;
}
return null;
}
}
public class BeanPostProcessDemo {
public static void main(String[] args) {
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
beanDefinitionBuilder.addPropertyValue("name", "wojiushiwo");
beanDefinitionBuilder.addPropertyValue("age", 20);
// 获取 AbstractBeanDefinition
AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
// 附加属性(
beanDefinition.setAttribute("name", "我是附加属性");
// 当前 BeanDefinition 来自哪里(辅助作用)
beanDefinition.setSource(BeanPostProcessDemo.class);
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.addBeanPostProcessor(new MyInstantiationBeanPostProcessor());
// 注册 User 的 BeanDefinition
beanFactory.registerBeanDefinition("user", beanDefinition);
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
}
输出结果:
User(name=abcd, age=20)
属性的真正赋值
if (pvs != null) {
//将从前面步骤得到的pvs 赋值到beanWrapper中以实现属性赋值,这部分具体源码这里不展开了
applyPropertyValues(beanName, mbd, bw, pvs);
}
来源:https://blog.csdn.net/zyxwvuuvwxyz/article/details/123271627


猜你喜欢
- 一、常见的锁策略1.1 乐观锁乐观锁:乐观锁假设认为数据一般情况下不会产生并发冲突,所以在数据进行提交更新的时候,才会正 式对数据是否产生并
- if判断integer的问题昨天在使用mybatis的if判断integer时遇见一个小问题:<if test="isCho
- Hadoop是什么?Hadoop是一个开发和运行处理大规模数据的软件平台,是Appach的一个用java语言实现开源软件框架,实现在大量计算
- 一、maven * 搭建使用Nexus进行搭建,网上教程很多,不多赘述了。二、gradle配置在build.gradle文件的根节点中添加以下
- 【漏洞通告】2月19日,NVD发布安全通告披露了jackson-databind由JNDI注入导致的远程代码执行漏洞(CVE-2020-88
- 一、题目描述题目实现:网络资源的断点续传功能。二、解题思路获取要下载的资源网址显示网络资源的大小上次读取到的字节位置以及未读取的字节数输入下
- pom.xml<dependency> <groupId>org.springframework.bo
- 反阈值二值化反阈值二值化与阈值二值化互为逆操作。在OpenCV中该类的实现依赖于threshold() 函数。下面是该函数的声明:thres
- 有些 SMTP 服务器要求在代表客户端发送电子邮件前验证客户端的身份。当此 SmtpClient 对象应该使用当前登录用
- 近日于LeetCode看题遇1114 按序打印,获悉一解法使用了Semaphore,顺势研究,记心得于此。此解视Semaphore为锁,以保
- 归并排序原理1.尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是1为止。⒉将相邻的两个子组
- 介绍使用mybatis时可以使用二级缓存提高查询速度,进而改善用户体验。使用redis做mybatis的二级缓存可是内存可控<如将单独
- 本文为大家分享了maven环境变量配置的具体方法,供大家参考,具体内容如下一、maven环境配置1.解压apache-maven
- 前言前面一篇我们介绍了使用 shared_preferences实现简单的键值对存储,然而我们还会面临更为复杂的本地存储。比如资讯类 App
- 双向链表(Doubly linked list)什么是双向链表?双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直
- android系统提供了Environment.getExternalStorageDirectory()接口获得存储器的路径,但是这个接口
- ImageView是用于界面上显示图片的控件。属性1、为ImageView设置图片①android:src="@drawable/
- spring boot版本和spring cloud版本框架版本SpringBoot2.3.12.RELEASESpringCloudHox
- 本文实例为大家分享了WebView实现文件下载功能的具体代码,供大家参考,具体内容如下本节引言本节给大家介绍的是WebView下载文件的知识
- 基数排序也是桶排序的一种,也是跟样本数据强相关的,且基数排序要求样本数据是非负的十进制数,如果有小数或者负数,那么代码将要大量重写!这就是不