Springboot扩展点系列_InstantiationAwareBeanPostProcessor

功能特性

1、虽然InstantiationAwareBeanPostProcessor继承于BeanPostProcessor,但是InstantiationAwareBeanPostProcessor的执行时机要稍早于BeanPostProcessor;

2、InstantiationAwareBeanPostProcessor有三个扩展方法,分别是:postProcessBeforeInstantiation()、postProcessAfterInstantiation()、postProcessProperties();

3、postProcessBeforeInstantiation()在Spring中Bean实例化前触发执行;

4、postProcessAfterInstantiation()、postProcessProperties()在Spring中Bean实例化后,属性注入前触发执行;

5、InstantiationAwareBeanPostProcessor继承于BeanPostProcessor的postProcessBeforeInitialization()和postProcessAfterInitialization()则在Spring中Bean实例化、属性注入完成后触发执行;

6、postProcessBeforeInstantiation()扩展点可以自定义个性化的Bean来替换掉目标Bean,需要注意的是替换掉目标Bean后,postProcessAfterInstantiation()会执行,其他的扩展点将不再触发;

7、postProcessAfterInstantiation()的返回值为布尔类型,如果返回值为true,则第三个扩展点postProcessProperties()会继续执行;如果返回值为false,则第三个扩展点postProcessProperties()将不再执行;

8、postProcessProperties()扩展点可以在目标Bean实例化后,属性注入前,对要注入的属性值内容进行更改,以替换掉原来的属性值;

实现方式

总的来说InstantiationAwareBeanPostProcessor扩展点的实现方式很简单,实现接口,重写相应的方法实现扩展逻辑,并用@Component注解标记实现类,其余的由Spring自动完成。下面通过示例逐步详细介绍:

1、定义一个Controller类(ExampleController),通过setter方法注入属性ExampService;

@RestController
@RequestMapping("/example")
@Slf4j
public class ExampleController {
    private String creator="gaox";
    private ExampleService exampleService;
    @Autowired
    public void setExampleService(ExampleService exampleService) {
        this.exampleService = exampleService;
        log.info("----ExampleController内的exampleService属性被注入");
    }
    public void setCreator(String creator) {
        this.creator = creator;
        log.info("----ExampleController内的creator属性被注入");
    }
    public String getCreator() {
    return creator;
    }
    public ExampleController() {
        log.info("----ExampleController无参构造方法被执行");
    }
}

2、定义ExampleService类,以便作为引用属性注入到ExampleController中;

@Service
@Slf4j
public class ExampleService {
    public ExampleService() {
        log.info("----ExampleService无参构造方法被执行");
    }
    public void test(){
        System.out.println("test");
    }
}

3、定义InstantiationAwareBeanPostProcessor接口的实现类示例类MyInstantiationAwareBeanPostProcessor,并重写InstantiationAwareBeanPostProcessor接口的三个扩展方法和继承于BeanPostProcessor接口的两个扩展方法;

@Component
@Slf4j
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
 
    @SneakyThrows
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanName.equals("exampleController")) {
            log.info("----postProcessBeforeInstantiation被执行:" + beanName);
            return null;
        }
        return null;
    }
 
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (beanName.equals("exampleController")) {
            log.info("----postProcessAfterInstantiation被执行:" + beanName);
        }
        return true;
    }
 
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (beanName.equals("exampleController")) {
           log.info("----postProcessProperties被执行:" + beanName);
            MutablePropertyValues  mutablePropertyValues=new MutablePropertyValues();
            mutablePropertyValues.addPropertyValue("creator","fanfu");
            pvs=mutablePropertyValues;
        }
        return pvs;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("exampleController")) {
            log.info("----postProcessBeforeInitialization---" + beanName);
            //如果特定的bean实例化完成后,还未执行InitializingBean.afterPropertiesSet()方法之前,有一些其他操作,可以在这里实现
        }
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("exampleController")) {
            log.info("----postProcessAfterInitialization---" + beanName);
            //如果特定的bean实例化完成,InitializingBean.afterPropertiesSet()方法执行后,有一些其他操作,可以在这里实现
        }
        return bean;
    }
}

4、编写单元测试验证InstantiationAwareBeanPostProcessor接口的功能特性;

@Test
public void test3(){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
    ExampleController bean = context.getBean(ExampleController.class);
    Assert.isTrue("fanfu".equals(bean.getCreator()),"属性替换失败");
    log.info("----"+bean.getCreator());
 
}

执行结果如下:

img

工作原理

注册时机

1、因为InstantiationAwareBeanPostProcessor接口继承于BeanPostProcessor接口,所以InstantiationAwareBeanPostProcessor接口的实现类的注册时机和BeanPostProcessor是一致的,因此很快就找到了InstantiationAwareBeanPostProcessor接口的实现类的注册入口,即org.springframework.context.support.AbstractApplicationContext#refresh—>registerBeanPostProcessors;

img

2、进入到AbstractApplicationContext#registerBeanPostProcessors方法内,会发现这段代码很干净,即依赖于PostProcessorRegistrationDelegate类的registerBeanPostProcessors()方法;

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
   PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

3、进入到PostProcessorRegistrationDelegate类的registerBeanPostProcessors()方法又是另一番洞天:大致是可以分为四步,第一步,获取所有实现BeanPostProcessor接口的实现类的名称,实现方式示例中的MyBeanPostProcessors就在其中;

img

第二步,提前注册BeanPostProcessorChecker,主要用途是用于Bean创建过程中的日志信息打印记录;

img

第三步,就是把所有的BeanPostProcessor接口的实现类,按照是否实现PriorityOrdered接口、是否实现Ordered接口、其他,分为三组;

img

最后一步内容很长,不过很简单,即按第二步分成的三类,依次注册,具体的顺序是:1:实现PriorityOrdered接口BeanPostProcessor接口的实现类、2:实现实现Ordered接口BeanPostProcessor接口的实现类、3:其他的BeanPostProcessor接口的实现类,其中MyInstantiationAwareBeanPostProcessor属于第三类;

img

总结,InstantiationAwareBeanPostProcessor接口的实现类的注册,其本质是把接口的实现类注入到Spring容器的一个集合里存起来,具体的注册逻辑在PostProcessorRegistrationDelegate#registerBeanPostProcessors()。

img

执行时机

从实现方式的示例的单元测试执行结果可以看出,InstantiationAwareBeanPostProcessor接口继承于BeanPostProcessor的postProcessBeforeInitialization()和postProcessAfterInitialization()扩展点的执行时机是在Bean(ExampleController)实例化、属性注入完成后触发执行的,其具体的工作原理可以参考Springboot的扩展点之BeanPostProcessor,下面就InstantiationAwareBeanPostProcessor接口的另外三个扩展点的执行时机进行分析。

1、从实现方式示例中,可知InstantiationAwareBeanPostProcessor的第一个扩展点postProcessBeforeInstantiation()是在Eean实例化前触发执行的,所以寻找其执行时机的第一步就要找到Bean实例化的入口,通过debug很快找到了这个位置 ,AbstractApplicationContext#refresh—>finishBeanFactoryInitialization();

img

2、进入到finishBeanFactoryInitialization()方法,会发现ExampleController这个Bean的实例化是在

DefaultListableBeanFactory#preInstantiateSingletons方法;

img

3、这里实际被调用的是DefaultListableBeanFactory#preInstantiateSingletons方法,进入到这个方法内,又调用了AbstractBeanFactory#getBean(),从这才算真正Bean的获取或创建的入品口口。这里大致介绍一下getBean()的逻辑:当获取某一个bean时,先查询缓存确定是否存在,若存在,则直接返回,若不存在,则开始创建Bean,若Bean内依赖了另外一个Bean,则是上述过程的一个递归。

img

4、进入到AbstractBeanFactory#getBean方法,发现又调用了AbstractBeanFactory#doGetBean

–>DefaultSingletonBeanRegistry#getSingleton()

–>AbstractAutowireCapableBeanFactory#createBean();

img

这里需要注意一下,用到了lambda表达式,即把下面的函数式接口的具体实现作为DefaultSingletonBeanRegistry#getSingleton()的第二个形参singletonFactory

传进去,在DefaultSingletonBeanRegistry#getSingleton()内,执行到singletonFactory.getObject()时触发下面lambda表达式内的createBean();(lambda表达式的应用在Spirng的源码中应用很广泛,所以对这块不太熟悉的小伙伴可以着重研究一下)

() -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      destroySingleton(beanName);
      throw ex;
   }
}
postProcessBeforeInstantiation()

5、源码分析本身并不难,难的是需要耐心,分析这么多了,实际上还未走到进入到InstantiationAwareBeanPostProcessor的扩展点,但是已经很接近了。进入到AbstractAutowireCapableBeanFactory#createBean()

—>AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation(),定睛一看第一个扩展点到了,具体且看下面的注释内容:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // 检查bean是不是合成的Bean,
      //InstantiationAwareBeanPostProcessor接口的实现类是否己注册
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
           //查询出目标Bean的Class实例
           Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
             //开始执行第一个扩展方法postProcessBeforeInstantiation
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}

具体的扩展点postProcessBeforeInstantiation()的执行也是朴实无华:查询出所有接口的实现类,然后循环执行;只一需要注意的是扩展点处的返回值处理,这个时候目标Bean(ExampleController)未实例化,这时可以自定义一个Bean对象作为返回值把目标Bean替换掉,那么后续的postProcessBeforeInitialization扩展点还会触发执行,而其他扩展点将会跳过不再执行;什么意思呢?简单点理解就是正常情况下Spring管理目标Bean会一步一步的实例化、属性注入、初始化,但你想要实现点个性化的东西,Spring就把这个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);
         if (result != null) {
            return result;
         }
      }
   }
   return null;
}
postProcessAfterInstantiation()

6、从AbstractAutowireCapableBeanFactory#createBean()

—>AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation()完成第一个扩展点的执行,继续往下走就是AbstractAutowireCapableBeanFactory#doCreateBean了,要找到第二个、第三个扩展点都在这里面;

img

7、进入到AbstractAutowireCapableBeanFactory#doCreateBean方法,如下图,instanceWrapper.getWrappedInstance()完成了目标Bean(ExampleController)的示例化,但是属性exampleService还未注入;

img

继续往下走,调用populateBean(),完成对已实例化的目标Bean(ExampleController)的属性注入;如图进入到populateBean()就开始了第二个扩展点postProcessAfterInstantiation()方法的执行;这里要注意一下返回值的类型为布尔类型:如果返回true,则会继续执行第三个扩展点;如果返回fase,则第三个扩展点不会执行,直接return跳出了当前方法;

img

postProcessProperties()

还是在AbstractAutowireCapableBeanFactory#populateBean方法中,第二个扩展点执行过且返回值为true,接着往下就会执行到第三个扩展点postProcessProperties();

img

第三个扩展点要着重说一下,第三个扩展触发执行的时候Bean已经实例化,但是未完成属性注入,但是这里可以在里替换掉即将注入的属性。在实现方式的示例代码ExampleController类中,定义了一个String类型的属性creator,默认值为"gaox",在MyInstantiationAwareBeanPostProcessor#postProcessProperties中,把“gaox”替换为“fanfu”,再看单元测试的执行结果,默认值“gaox”被替换成了“fanfu”;

应用场景

其实了解了InstantiationAwareBeanPostProcessorr的功能特性、实现方式和工作原理,在遇到类似的业务需求的时候都可以应用这些扩展点,这里举一个平时开发中经用到但是应该没有注意到的一个Spring内部经典实现AutowiredAnnotationBeanPostProcessor。

通过的UML类图,可以看到AutowiredAnnotationBeanPostProcessor继承于InstantiationAwareBeanPostProcessorAdapter,而InstantiationAwareBeanPostProcessorAdapter又实现了SmartInstantiationAwareBeanPostProcessor接口,SmartInstantiationAwareBeanPostProcessor接口又继承了InstantiationAwareBeanPostProcessor。

img

AutowiredAnnotationBeanPostProcessor又实现了InstantiationAwareBeanPostProcessor的postProcessProperties();实现方式中示例代码ExampleController类的exampleService属性用@Autowired注解标记后,实际的注入实现逻辑就在AutowiredAnnotationBeanPostProcessor的postProcessProperties()内,有兴趣的小伙伴可以继续深入下去探寻一翻。

@Override
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值