前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring源码解析(十二)Spring扩展接口SmartInstantiationAwareBeanPostProcessor解析

Spring源码解析(十二)Spring扩展接口SmartInstantiationAwareBeanPostProcessor解析

作者头像
石臻臻的杂货铺[同名公众号]
发布2021-07-14 10:02:00
1.9K0
发布2021-07-14 10:02:00
举报
文章被收录于专栏:kafka专栏

之前我们分析了 InstantiationAwareBeanPostProcessor、BeanPostProcessor、今天来分析一下SmartInstantiationAwareBeanPostProcessor的用法;

SmartInstantiationAwareBeanPostProcessor 继承自 InstantiationAwareBeanPostProcessor; 但是SmartInstantiationAwareBeanPostProcessor多了一个三个方法

代码语言:javascript
复制
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {

// 预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null
	Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException;
// 选择合适的构造器,比如目标对象有多个构造器,在这里可以进行一些定制化,选择合适的构造器
// beanClass参数表示目标实例的类型,beanName是目标实例在Spring容器中的name
// 返回值是个构造器数组,如果返回null,会执行下一个PostProcessor的determineCandidateConstructors方法;否则选取该PostProcessor选择的构造器
	Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException;
// 获得提前暴露的bean引用。主要用于解决循环引用的问题
// 只有单例对象才会调用此方法
	Object getEarlyBeanReference(Object bean, String beanName) throws BeansException;
}

getEarlyBeanReference


这个方法见名思意就是获取提前引用的意思了,Spring中解决循环引用的时候有调用这个方法, 关于循环引用请看 分析一个Spring循环引用失败的问题

但是我还是想再分析一下它的调用时机

getEarlyBeanReference调用时机


准备两个类,让他们相互引用

代码语言:javascript
复制
 <bean id="circulationa" class="src.bean.CirculationA">
    <property name="circulationB" ref="circulationb"/>
  </bean>
  <bean id="circulationb" class="src.bean.CirculationB" >
    <property name="circulationA" ref="circulationa"/>
  </bean>

启动; 1. 加载circulationa,然后将调用了代码,提前将singleto暴露出去,但是这个时候只是getEarlyBeanReference还没有被调用; 因为没有出现循环引用的情况;现在放入缓存是为了预防有循环引用的情况可以通过这个getEarlyBeanReference获取对象;

代码语言:javascript
复制
// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

2.然后填充属性值;调用下面的方法,在填充属性的时候发现引用了circulationb;然后就去获取circulationb来填充

代码语言:javascript
复制
populateBean(beanName, mbd, instanceWrapper);

3.加载circulationb, 执行的操作跟 1,2一样; circulationb发现了引用了circulationa;然后直接调用getSingleton获取circulationa;

代码语言:javascript
复制
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//这个地方就是调用getEarlyBeanReference的地方了;
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}

这一步返回的就是 getEarlyBeanReference得到的值; 4.执行getEarlyBeanReference方法

代码语言:javascript
复制
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
					if (exposedObject == null) {
						return null;
					}
				}
			}
		}
		return exposedObject;
	}

4.1 一般情况下,如果系统中没有SmartInstantiationAwareBeanPostProcessor接口;就是直接返回exposedObject什么也不做; 4.2.所以利用SmartInstantiationAwareBeanPostProcessor可以改变一下提前暴露的对象;

5.拿到引用了之后…就不分析了…

determineCandidateConstructors调用时机


检测Bean的构造器,可以检测出多个候选构造器,再有相应的策略决定使用哪一个,如AutowiredAnnotationBeanPostProcessor实现将自动扫描通过@Autowired/@Value注解的构造器从而可以完成构造器注入

predictBeanType

预测Bean的类型,返回第一个预测成功的Class类型,如果不能预测返回null;当你调用BeanFactory.getType(name)时当通过Bean定义无法得到Bean类型信息时就调用该回调方法来决定类型信息;BeanFactory.isTypeMatch(name, targetType)用于检测给定名字的Bean是否匹配目标类型(如在依赖注入时需要使用);

利用SmartInstantiationAwareBeanPostProcessor做点啥?


在Spring中默认实现了它的有两个实现类; AbstractAutoProxyCreator InstantiationAwareBeanPostProcessorAdapter;这个只是但是的实现了一下所有接口,但是都是直接返回并没有做什么事情; 那我们主要分析一下AbstractAutoProxyCreator做了啥?

AbstractAutoProxyCreator


TODO…涉及到AOP 等下次分析AOP的时候再回来分析

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018/05/17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • getEarlyBeanReference
    • getEarlyBeanReference调用时机
      • determineCandidateConstructors调用时机
        • predictBeanType
        • 利用SmartInstantiationAwareBeanPostProcessor做点啥?
        • AbstractAutoProxyCreator
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档