写点什么

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

  • 2022 年 9 月 08 日
    江西
  • 本文字数:3031 字

    阅读完需:约 10 分钟

作者石臻臻,CSDN 博客之星 Top5Kafka Contributornacos Contributor华为云 MVP,腾讯云 TVP,滴滴 Kafka 技术专家 KnowStreaming, 《Kafka 运维与实战宝典》电子书作者。领取《Kafka 运维与实战宝典》PDF 请联系石臻臻


KnowStreaming 是滴滴开源的Kafka运维管控平台, 有兴趣一起参与参与开发的同学,但是怕自己能力不够的同学,可以联系我,当你导师带你参与开源!

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

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

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;}
复制代码

1getEarlyBeanReference


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

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

getEarlyBeanReference 调用时机


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

 <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 获取对象;

// 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 来填充

populateBean(beanName, mbd, instanceWrapper);
复制代码

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

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 方法

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 是否匹配目标类型(如在依赖注入时需要使用);

2 利用 SmartInstantiationAwareBeanPostProcessor 做点啥?


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

3AbstractAutoProxyCreator


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

发布于: 刚刚阅读数: 5
用户头像

关注公众号: 石臻臻的杂货铺 获取最新文章 2019.09.06 加入

进高质量滴滴技术交流群,只交流技术不闲聊 加 szzdzhp001 进群 20w字《Kafka运维与实战宝典》PDF下载请关注公众号:石臻臻的杂货铺

评论

发布
暂无评论
Spring源码解析(十二)Spring扩展接口SmartInstantiationAwareBeanPostProcessor解析_spring_石臻臻的杂货铺_InfoQ写作社区