写点什么

Spring 源码解析 (十一)Spring 扩展接口 InstantiationAwareBeanPostProcessor 解析

  • 2022 年 9 月 06 日
    江西
  • 本文字数:8133 字

    阅读完需:约 27 分钟

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


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

之前我们有分析 BeanPostProcessor 接口,今天要分析的 InstantiationAwareBeanPostProcessor 是继承了 BeanPostProcessor 接口的;

Part1、InstantiationAwareBeanPostProcessor


InstantiationAwareBeanPostProcessor 代表了 Spring 的另外一段生命周期:实例化。先区别一下 Spring Bean 的实例化和初始化两个阶段的主要作用:

1、实例化----实例化的过程是一个创建 Bean 的过程,即调用 Bean 的构造函数,单例的 Bean 放入单例池中

2、初始化----初始化的过程是一个赋值的过程,即调用 Bean 的 setter,设置 Bean 的属性

之前的 BeanPostProcessor 作用于过程(2)前后,现在的 InstantiationAwareBeanPostProcessor 则作用于过程(1)前后;

InstantiationAwareBeanPostProcessor 接口继承 BeanPostProcessor 接口,它内部提供了 3 个方法,再加上 BeanPostProcessor 接口内部的 2 个方法,所以实现这个接口需要实现 5 个方法。InstantiationAwareBeanPostProcessor 接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
 Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
 boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;  PropertyValues postProcessPropertyValues(   PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;}
复制代码

现在我们从源码层面分析一下,上面的执行时机

1.InstantiationAwareBeanPostProcessor 什么时候被注册?


InstantiationAwareBeanPostProcessor 继承了 BeanPostProcessor 接口;所以他有 BeanPostProcessor 的特性;注册和使用可以看前面的文章扩展接口BeanPostProcessors源码分析

首先实例化 BeanPostProcessors 类型的 bean;才会实例化剩余 单例并且非懒加载的 bean;因为

@Override public void refresh() throws BeansException, IllegalStateException { // Register bean processors that intercept bean creation.    registerBeanPostProcessors(beanFactory);     // Instantiate all remaining (non-lazy-init) singletons.    finishBeanFactoryInitialization(beanFactory); }
复制代码

跟一遍本次代码执行流程

2.执行 createBean,调用的开端

在 createBean 方法里面有个 resolveBeforeInstantiation 方法

@Override protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.   Object bean = resolveBeforeInstantiation(beanName, mbdToUse);   if (bean != null) {    return bean;   } //省略.... Object beanInstance = doCreateBean(beanName, mbdToUse, args); return beanInstance;
 }
复制代码

上面代码里面看到,在执行 doCreateBean 之前有 resolveBeforeInstantiation 方法;doCreateBean 是创建 bean 的方法;resolveBeforeInstantiation 是 判断执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 的接方法实现;下面看看执行的依据:

3.执行 postProcessBeforeInstantiation 方法的时机


/**  * Apply before-instantiation post-processors, resolving whether there is a  * before-instantiation shortcut for the specified bean.  * @param beanName the name of the bean  * @param mbd the bean definition for the bean  * @return the shortcut-determined bean instance, or {@code null} if none  */ protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {  Object bean = null;  //如果beforeInstantiationResolved还没有设置或者是false(说明还没有需要在实例化前执行的操作)  if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {   // 判断是否有注册过InstantiationAwareBeanPostProcessor类型的bean   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {    Class<?> targetType = determineTargetType(beanName, mbd);    if (targetType != null) {     //执行     bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);     if (bean != null) {      bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);     }    }   }   mbd.beforeInstantiationResolved = (bean != null);  }  return bean; }
复制代码


protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {  for (BeanPostProcessor bp : getBeanPostProcessors()) {   if (bp instanceof InstantiationAwareBeanPostProcessor) {    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;    Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);    //只要有一个result不为null;后面的所有 后置处理器的方法就不执行了,直接返回(所以执行顺序很重要)    if (result != null) {     return result;    }   }  }  return null; }
复制代码


@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)   throws BeansException {
  Object result = existingBean;  for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {   result = beanProcessor.postProcessAfterInitialization(result, beanName);   //如果返回null;后面的所有 后置处理器的方法就不执行,直接返回(所以执行顺序很重要)   if (result == null) {    return result;   }  }  return result; }
复制代码

上面代码说明:

  1. 如果 postProcessBeforeInstantiation 方法返回了 Object 是 null;那么就直接返回,调用 doCreateBean 方法();

  2. 如果 postProcessBeforeInstantiation 返回不为 null;说明修改了 bean 对象;然后这个时候就立马执行 postProcessAfterInitialization 方法(注意这个是初始化之后的方法,也就是通过这个方法实例化了之后,直接执行初始化之后的方法;中间的实例化之后 和 初始化之前都不执行);

  3. 在调用 postProcessAfterInitialization 方法时候如果返回 null;那么就直接返回,调用 doCreateBean 方法();(初始化之后的方法返回了 null,那就需要调用 doCreateBean 生成对象了)

  4. 在调用 postProcessAfterInitialization 时返回不为 null;那这个 bean 就直接返回给 ioc 容器了 初始化之后的操作 是这里面最后一个方法了;

  5. 通过上面的描述,我们其实可以在这里生成一个代理类;

3.1 写一个例子让 postProcessBeforeInstantiation 返回一个代理类

下面用 cglib 动态代理生成一个代理类:

public class TestFb  {    public void dosomething() {        System.out.print("执行了dosomething.......\n");    }}
复制代码


public class MyMethodInterceptor implements MethodInterceptor {    @Override    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {        System.out.println("目标方法前:" + method+"\n");        Object object = methodProxy.invokeSuper(o, objects);        System.out.println("目标方法后:" + method+"\n");        return object;    }}
复制代码


public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessBeforeInstantiation\n");        //利用 其 生成动态代理        if(beanClass==TestFb.class){            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(beanClass);            enhancer.setCallback(new MyMethodInterceptor());            TestFb testFb = (TestFb)enhancer.create();            System.out.print("返回动态代理\n");            return testFb;        }        return null;    }
    @Override    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessAfterInstantiation\n");
        return false;    }
    @Override    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessPropertyValues\n");        return pvs;    }
    @Override    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessBeforeInitialization\n");
        return bean;    }
    @Override    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessAfterInitialization\n");
        return bean;    }}
复制代码

然后启动


    public static void main(String[] args) throws Exception {               ApplicationContext ac = new ClassPathXmlApplicationContext("SpringContextConfig.xml");        TestFb testFb = ac.getBean(TestFb.class);        testFb.dosomething();    }
复制代码

输出结果:

beanName:tfb执行..postProcessBeforeInstantiation返回动态代理beanName:tfb执行..postProcessAfterInitialization目标方法前:public void src.factorybean.TestFb.dosomething()
执行了dosomething.......目标方法后:public void src.factorybean.TestFb.dosomething()
复制代码

结果很明显了,postProcessBeforeInstantiation 生成并返回了代理类;就直接执行 初始化之后的操作 postProcessAfterInitialization;没有执行 实例化之后 postProcessAfterInstantiation 也没执行 初始化之前 postProcessBeforeInitialization

这个例子将讲解的是 postProcessBeforeInstantiation 返回了对象,那我们继续分享,这个方法返回的是 null 的情况

4.postProcessAfterInstantiation 调用的地方

代码往后面执行走到了 populateBean 里面;这个主要是给 bean 填充属性的;实例化已经在 pupulateBean 之外已经完成了

  //实例化bean;选择不同策略来实例化bean instanceWrapper = createBeanInstance(beanName, mbd, args);
复制代码


protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
  //省略。。。。 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {   for (BeanPostProcessor bp : getBeanPostProcessors()) {    if (bp instanceof InstantiationAwareBeanPostProcessor) {     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;     //执行postProcessAfterInstantiation方法     if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {      continueWithPropertyPopulation = false;      break;     }    }   }  }//省略....
//下面的代码是判断是否需要执行postProcessPropertyValues;改变bean的属性boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();  boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
  if (hasInstAwareBpps || needsDepCheck) {   PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);   if (hasInstAwareBpps) {    for (BeanPostProcessor bp : getBeanPostProcessors()) {     if (bp instanceof InstantiationAwareBeanPostProcessor) {      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;      pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);      if (pvs == null) {       return;      }     }    }   }   if (needsDepCheck) {    checkDependencies(beanName, mbd, filteredPds, pvs);   }  }
//这里才是正在讲 属性值  真正的设置的我们的实例对象里面;之前postProcessPropertyValues这个还只是单纯的改变PropertyValues//最后还是要通过PropertyValues 设置属性到实例对象里面的  applyPropertyValues(beanName, mbd, bw, pvs);  
}

复制代码

这个 postProcessAfterInstantiation 返回值要注意,因为它的返回值是决定要不要调用 postProcessPropertyValues 方法的其中一个因素(因为还有一个因素是 mbd.getDependencyCheck());如果该方法返回 false,并且不需要 check,那么 postProcessPropertyValues 就会被忽略不执行;如果返回 true,postProcessPropertyValues 就会被执行

##5.postProcessPropertyValues 调用的地方代码还是看 populateBean 方法里面的;而且调用的条件上面也说了,那么我们分析一下这个方法能做什么事情呢?

例子:将上面的例子中的 TestFb 新增一个属性值 a

public class TestFb  {    private String a;
    public String getA() {        return a;    }
    public void setA(String a) {        this.a = a;    }
    public void dosomething() {        System.out.print("执行了dosomething.......\n");    }}
复制代码

config.xml 中配置一下属性

<bean id="tfb" class="src.factorybean.TestFb">    <property name="a" value="xml中配置的" />  </bean>
复制代码

修改 postProcessPropertyValues 方法;用于修改属性

 @Override    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessAfterInstantiation\n");  //这里一定要返回true        return true;    }
    @Override    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {        System.out.print("beanName:"+beanName+"执行..postProcessPropertyValues\n");        if(bean instanceof TestFb){            //修改bean中a 的属性值            PropertyValue value = pvs.getPropertyValue("a");            System.out.print("修改之前 a 的value是:"+value.getValue()+"\n");            value.setConvertedValue("我修改啦");            return pvs;        }        return pvs;    }

复制代码

启动的时候输出一下属性 a 的值:


        TestFb testFb = ac.getBean(TestFb.class);        testFb.dosomething();        System.out.println(  testFb.getA());
复制代码

结果

beanName:tfb执行..postProcessBeforeInstantiationbeanName:tfb执行..postProcessAfterInstantiationbeanName:tfb执行..postProcessPropertyValues修改之前 a 的value是:TypedStringValue: value [xml中配置的], target type [null]beanName:tfb执行..postProcessBeforeInitializationbeanName:tfb执行..postProcessAfterInitialization执行了dosomething.......我修改啦
复制代码

就是这样,postProcessPropertyValues 修改属性,但是要注意 postProcessAfterInstantiation 返回 true;

然后初始化的那两个方法在一问中已经分析了,这里就不再讲了;

所以总结再贴一遍:

5:总结

  1. InstantiationAwareBeanPostProcessor 接口继承 BeanPostProcessor 接口,它内部提供了 3 个方法,再加上 BeanPostProcessor 接口内部的 2 个方法,所以实现这个接口需要实现 5 个方法。InstantiationAwareBeanPostProcessor 接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置

  2. postProcessBeforeInstantiation 方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是 Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有 postProcessAfterInitialization 方法会调用,其它方法不再调用;否则按照正常的流程走

  3. postProcessAfterInstantiation 方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是 null。因为它的返回值是决定要不要调用 postProcessPropertyValues 方法的其中一个因素(因为还有一个因素是 mbd.getDependencyCheck());如果该方法返回 false,并且不需要 check,那么 postProcessPropertyValues 就会被忽略不执行;如果返回 true,postProcessPropertyValues 就会被执行

  4. postProcessPropertyValues 方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果 postProcessAfterInstantiation 方法返回 false,该方法可能不会被调用。可以在该方法内对属性值进行修改

  5. 父接口 BeanPostProcessor 的 2 个方法 postProcessBeforeInitialization 和 postProcessAfterInitialization 都是在目标对象被实例化之后,并且属性也被设置之后调用的

  6. Instantiation 表示实例化,Initialization 表示初始化。实例化的意思在对象还未生成,初始化的意思在对象已经生成

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

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

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

评论

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