Spring的后处理器-BeanPostProcessor跟BeanFactoryPostProcessors

        最近在重读spring源码(为何要重读?由于不得不认可,去年跟着《深刻解析sping源码》一书过了一遍spring的源码,除了满脑壳都是各类BeanFactory跟BeanDefinition外,真的没什么收获...),spring

而第二遍因为是分模块分功能点去看,有了针对性,再加上以前囫囵吞枣的那一遍给我带来的总体认识,这一次顺畅了许多,对spring的理解亦深刻了下去。因此说,阅读源码真的能带给人不少的收获,app

并且不止于代码。后面会专门找个合适的时机对本身学习以及阅读源码这个过程作个总结,今天先聊重点:Spring的后处理器是如何发挥做用的框架

 

        零:什么是后处理器                                                                                                                                                                                  

        Spring的后处理器只要有两大类,一个是针对BeanDefinition的容器级别的后处理器 - BeanFactoryPostProcessor(后面简称BFPP);一个是针对getBean操做得到的对象的后处理器 -post

BeanPostProcessor(后面简称BPP)。学习

         此两个后处理器不一样之处主要有三点:this

        一、触发时机不一样,前者BFPP是在容器refresh方法中调用,然后者实际调用时机是在getBean方法获取对象时调用;spa

        二、因触发时机不一样致使两者处理的对象不一样。BFPP处理的是解析完配置文件后注册在容器中的BeanDefinition,而BPP处理的是经过反射生成code

的实例Bean;对象

        三、接口样式不一样,BFPP只有一个后处理方法,而BPP有一个前置处理方法一个后置处理方法。blog

        接口以下所示:

 1 public interface BeanFactoryPostProcessor {
 2 
 3     void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
 4 
 5 }
 6 
 7 
 8 public interface BeanPostProcessor {
 9 
10     default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
11         return bean;
12     }
13 
14     default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
15         return bean;
16     }
17 
18 }

 

        一:BeanFactoryPostProcessor                                                                                                                                                                    

        在ApplicationContext容器初始化的核心方法refresh方法中,初始化完BeanFactory后会执行invokeBeanFactoryPostProcessors方法,就是在此方法中完成了对BFPP的调用。代码以下所示:

1 protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
2         PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
3 
4         if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
5             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
6             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
7         }
8 }

        能够知道,完成后处理器调用的方法是第二行的代码。此处请记住这个类PostProcessorRegistrationDelegate,它是处理后处理器的核心类。对于此处的方法invokeBeanFactoryPostProcessors,

代码很长,就不贴出来了,下面只作一些简单的梳理。

        一、先判断当前BeanFactory是否是BeanDefinitionRegistry,若是是则将实现BeanDefinitionRegistryPostProcessor(简称BDRPP)接口的类找到,按顺序执行后处理器的方法。此BDRPP接口是BFPP

接口的子类。其做用是什么?为何要单独对其进行处理?看其后置方法即可只其一二。它的后置处理方法参数是一个BeanDefinitionRegistry,它是作什么用的?往容器中注册BeanDefinition的。因此此

处单独处理BDRPP的缘由也就基本明了了 - 就是根据实际须要在此处建立BeanDefinition往容器中注册的,即留了一个往容器中注册bean的后门。

        二、再获取全部实现了BeanFactoryPostProcessor接口的子类,按照顺序执行后处理器方法。

 

        二:BeanPostProcessor                                                                                                                                                                         

        BPP后处理器的处理,相比BFPP多了一步,BFPP是在ApplicationContext容器初始化的时候就调用了,而BPP是在容器初始化时注册,调用则是在getBean获取对象实例时触发。

        一、BPP的注册

        一样是在refresh方法中,就在调用BFPP方法的下面,调用了注册BPP的方法  - registerBeanPostProcessors方法。

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

        看到熟悉的面孔了吧,对,仍是它,那个调用BFPP的类!

        此方法代码一样很多,此处就不贴出来了,主要梳理一下代码逻辑:

        1)、首先是获取BPP实例。获取BPP子类的套路跟上文中获取BFPP子类的套路基本同样,先经过类的type获取到注册到当前容器中的全部的子类,而后根据是否实现了PriorityOrdered、Ordered接口

对其进行分类、排序,最后再经过beanFactory的getBean方法获取到BeanPostProcessor的实例对象;

        2)、注册BPP实例。注册的顺序是先注册实现了PriorityOrdered的实例,再注册Ordered的实例,最后注册普通的BPP。此处的注册是指将这个BPP放入AbstractBeanFactory维护的一个成员变量中,

此变量是一个CopyOnWriteArrayList。在加入以前会先执行一下remove方法,防止重复加入。

 

        二、BPP的调用

         BeanFactory的多个getBean方法,大可能是在AbstractBeanFactory方法中实现,而最终建立bean实例,则是在AbstractAutowireCapableBeanFactory中实现。在此类的doCreateBean方法的initializeBean

方法中,实现了对BPP的调用。方法代码以下所示:

 1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 2         if (System.getSecurityManager() != null) {
 3             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 4                 invokeAwareMethods(beanName, bean);
 5                 return null;
 6             }, getAccessControlContext());
 7         }
 8         else {
 9             invokeAwareMethods(beanName, bean);
10         }
11 
12         Object wrappedBean = bean;
13         if (mbd == null || !mbd.isSynthetic()) {
14             wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
15         }
16 
17         try {
18             invokeInitMethods(beanName, wrappedBean, mbd);
19         }//此处catch异常处理代码已被BZ去掉
20         
21         if (mbd == null || !mbd.isSynthetic()) {
22             wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
23         }
24 
25         return wrappedBean;
26 }

        由代码可知,BPP的前置、后置方法,分别在第14行、第22行被调用,返回的结果即建立出来的bean。

 

        三:小结                                                                                                                                                                                                     

         经过这两大类后处理器,能充分感受到Spring对于框架扩展性作出的努力。后处理器理解实现过程不难,难的是如何在实际工做中灵活的利用spring的这个扩展性解决项目中的问题,或者利用其给

开发带来效率上的提高。经常使用的场景好比过滤bean的某些内容,对其进行特殊处理(实际工做中BZ也没用过 ><)。以上就是BZ对spring中后处理器的理解,可能因水平或者思考角度等缘由有理解不到位的

地方,欢迎各位猿友们批评指正!

         就此别过,下期初步打算讲讲AOP的相关原理。

相关文章
相关标签/搜索