前言

  开心一刻

    小明:“妈,我被公司开除了”,妈:“啊,为什么呀?”,
小明:“我骂董事长是笨蛋,公司召开高层会议还要起诉我”,妈:“告你诽谤是吧?”,小明:“不是,他们说要告我泄露公司机密”



BeanPostProcessor定义

  不管三七二十一,我们先来看看它的定义,看看spring是如何描述BeanPostProcessor的
/* * Copyright 2002-2016 the original author or authors. * * Licensed under
the Apache License, Version 2.0 (the "License"); * you may not use this file
except in compliance with the License. * You may obtain a copy of the License
at * *http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by
applicable law or agreed to in writing, software * distributed under the
License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. * See the License for the specific
language governing permissions and * limitations under the License.*/ package
org.springframework.beans.factory.config;import
org.springframework.beans.BeansException;import
org.springframework.lang.Nullable;/** * 允许对新的bean示例进行自定义的修改,例如检查标志接口或进行代理封装 * *
spring上下文会在它的beng定义中自动检测BeanPostProcessor实例,并将它们应用于随后创建的每一个bean实例 * * implement
{@link #postProcessAfterInitialization}. *
通常,通过实现BeanPostProcessor的postProcessBeforeInitialization方法(配合标记接口,如@Autowired)来填充bean实例,
* 通过BeanPostProcessor的postProcessAfterInitialization方法进行bean实例的代理 **/ public
interface BeanPostProcessor { /** *
在bean实例的初始化方法(例如InitializingBean的afterPropertiesSet或自定义的init-method)回调之前, *
spring会应用此方法到bean实例上。一般用于bean实例的属性值的填充 * Apply this BeanPostProcessor to the
given new bean instance <i>before</i> any bean * initialization callbacks (like
InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The
bean will already be populated with property values. * The returned bean
instance may be a wrapper around the original. * <p>The default implementation
returns the given {@code bean} as-is. * @param bean the new bean instance *
@param beanName the name of the bean * @return the bean instance to use, either
the original or a wrapped one; * if {@code null}, no subsequent
BeanPostProcessors will be invoked *@throws
org.springframework.beans.BeansException in case of errors *@see
org.springframework.beans.factory.InitializingBean#afterPropertiesSet*/
@Nullabledefault Object postProcessBeforeInitialization(Object bean, String
beanName)throws BeansException { return bean; } /** *
在bean实例的初始化方法(例如InitializingBean的afterPropertiesSet或自定义的init-method)回调之后, *
spring会应用此方法到bean实例上。 *
在有FactoryBean时,此方法会在FactoryBean实例与FactoryBean的目标对象创建时各调用一次 * Apply this
BeanPostProcessor to the given new bean instance <i>after</i> any bean *
initialization callbacks (like InitializingBean's {@code afterPropertiesSet} *
or a custom init-method). The bean will already be populated with property
values. * The returned bean instance may be a wrapper around the original. *
<p>In case of a FactoryBean, this callback will be invoked for both the
FactoryBean * instance and the objects created by the FactoryBean (as of Spring
2.0). The * post-processor can decide whether to apply to either the
FactoryBean or created * objects or both through corresponding {@code bean
instanceof FactoryBean} checks. * <p>This callback will also be invoked after a
short-circuiting triggered by a * {@link
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method, *
in contrast to all other BeanPostProcessor callbacks. * <p>The default
implementation returns the given {@code bean} as-is. * @param bean the new bean
instance *@param beanName the name of the bean * @return the bean instance to
use, either the original or a wrapped one; * if {@code null}, no subsequent
BeanPostProcessors will be invoked *@throws
org.springframework.beans.BeansException in case of errors *@see
org.springframework.beans.factory.InitializingBean#afterPropertiesSet *@see
org.springframework.beans.factory.FactoryBean*/ @Nullable default Object
postProcessAfterInitialization(Object bean, String beanName)throws
BeansException {return bean; } } View Code

  简单点来理解,就是spring会自动从它的所有的bean定义中检测BeanPostProcessor类型的bean定义,然后实例化它们,再将它们应用于随后创建的每一个bean实例,在bean实例的初始化方法回调之前调用BeanPostProcessor的postProcessBeforeInitialization的方法(进行bean实例属性的填充),在bean实例的初始化方法回调之后调用BeanPostProcessor的postProcessAfterInitialization的方法(可以进行bean实例的代理封装)

应用示例


  我们先来看个简单的示例,注意:由于spring只是从spring容器中的bean定义中自动检测BeanPostProcessor类型的bean定义,所以我们自定义的BeanPostProcessor要通过某种方式注册到spring容器

  MyBeanPostProcessor
@Component public class MyBeanPostProcessor implements BeanPostProcessor {
public MyBeanPostProcessor () { System.out.println("MyBeanPostProcessor
实例化......"); } @Override public Object postProcessBeforeInitialization(Object
bean, String beanName)throws BeansException { System.out.println(
"spring中bean实例:" + beanName + " 初始化之前处理......"); return bean; } @Override public
Object postProcessAfterInitialization(Object bean, String beanName)throws
BeansException { System.out.println("spring中bean实例:" + beanName + "
初始化之后处理......"); return bean; } } View Code
  AnimalConfig
@Configuration public class AnimalConfig { public AnimalConfig() {
System.out.println("AnimalConfig 实例化"); } @Bean public Dog dog() { return new
Dog(); } } View Code
  Dog
public class Dog { private String name; public Dog() { System.out.println("Dog
实例化......"); } public String getName() { return name; } public void
setName(String name) {this.name = name; } } View Code
  完整实例工程:spring-boot-BeanPostProcessor
<https://gitee.com/youzhibing/spring-boot-2.0.3/tree/master/spring-boot-BeanPostProcessor>
 我们来看看启动结果



  有人可能会说了:“你是个逗比把,你举的这个例子有什么用? 实际上,根本就不会出现BeanPostProcessor的这样用法!” 
有这样的疑问非常正常,示例中的BeanPostProcessor的两个方法:postProcessBeforeInitialization、postProcessAfterInitialization没做任何的处理,都只是直接返回bean,这不就是:脱了裤子放屁?


  我们细看下,会发现postProcessBeforeInitialization、postProcessAfterInitialization中各多了一行打印(
),其实示例只是验证下Spring对BeanPostProcessor的支持、BeanPostProcessor的两个方法的执行时机,是否如BeanPostProcessor
的注释所说的那样,实际应用中肯定不会这么用的。那问题来了:BeanPostProcessor能用来干什么?
回答这个问题之前,我们先来看看spring对BeanPostProcessor的底层支持

源码解析

  BeanPostProcessor的实例化与注册  

    很明显,我们从spring的启动过程的refresh方法开始,如下图

 


    此时spring容器中所有的BeanPostProcessor都进行了实例化,并注册到了beanFactory的beanPostProcessors属性中

    registerBeanPostProcessors
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory
beanFactory, AbstractApplicationContext applicationContext) { String[]
postProcessorNames= beanFactory.getBeanNamesForType(BeanPostProcessor.class,
true, false); // Register BeanPostProcessorChecker that logs an info message
when// a bean is created during BeanPostProcessor instantiation, i.e. when // a
bean is not eligible for getting processed by all BeanPostProcessors. int
beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 +
postProcessorNames.length; beanFactory.addBeanPostProcessor(new
BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));// Separate
between BeanPostProcessors that implement PriorityOrdered,// Ordered, and the
rest.// 将所有BeanPostProcessor
bean定义分三类:实现了PriorityOrdered、实现了Ordered,以及剩下的常规BeanPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors =new ArrayList<>(); List
<BeanPostProcessor> internalPostProcessors =new ArrayList<>(); List<String>
orderedPostProcessorNames =new ArrayList<>(); List<String>
nonOrderedPostProcessorNames =new ArrayList<>(); for (String ppName :
postProcessorNames) {if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class
)) {// 实例化实现了PriorityOrdered接口的BeanPostProcessor BeanPostProcessor pp =
beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);if (pp instanceof
MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } }else if
(beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName); }else {
nonOrderedPostProcessorNames.add(ppName); } }// First, register the
BeanPostProcessors that implement PriorityOrdered.//
注册实现了PriorityOrdered接口的BeanPostProcessor到beanFactory的beanPostProcessors属性中
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);// Next,
register the BeanPostProcessors that implement Ordered. List<BeanPostProcessor>
orderedPostProcessors =new ArrayList<>(); for (String ppName :
orderedPostProcessorNames) {// 实例化实现了Ordered接口的BeanPostProcessor
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);if (pp instanceof
MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } }//
注册实现了Ordered接口的BeanPostProcessor到beanFactory的beanPostProcessors属性中
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);// Now, register
all regular BeanPostProcessors. List<BeanPostProcessor>
nonOrderedPostProcessors =new ArrayList<>(); for (String ppName :
nonOrderedPostProcessorNames) {// 实例化剩下的所有的常规的BeanPostProcessors
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);if (pp instanceof
MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } }
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);// Finally,
re-register all internal BeanPostProcessors.//
注册所有常规的的BeanPostProcessor到beanFactory的beanPostProcessors属性中
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);// Re-register
post-processor for detecting inner beans as ApplicationListeners,// moving it
to the end of the processor chain (for picking up proxies etc).
beanFactory.addBeanPostProcessor(new
ApplicationListenerDetector(applicationContext)); } View Code
  BeanPostProcessor的生效时机

    前面我们已经知道,spring会应用BeanPostProcessor于随后创建的每一个bean实例,具体spring是如何做到的了,我们仔细来看看


    finishBeanFactoryInitialization方法实例化所有剩余的、非延迟初始化的单例(默认情况下spring的bean都是非延迟初始化单例),具体如下



BeanPostProcessor应用场景


  其实只要我们弄清楚了BeanPostProcessor的执行时机:在bean实例化之后、初始化前后被执行,允许我们对bean实例进行自定义的修改;只要我们明白了这个时机点,我们就能分辨出BeanPostProcessor适用于哪些需求场景,哪些需求场景可以用BeanPostProcessor来实现


  spring中有很多BeanPostProcessor的实现,我们接触的比较多的自动装配:AutowiredAnnotationBeanPostProcessor也是BeanPostProcessor的实现之一,关于自动装配我会在下篇博文中与大家一起探索

总结

  spring中bean的生命周期如下图

    引用自:Spring实战系列(三)-BeanPostProcessor的妙用
<https://blog.csdn.net/geekjoker/article/details/79868945>


友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信