BeanPostProcessor详解
转自: https://www.jianshu.com/p/d26e8ec9c077?
BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。BeanPostProcessor的源码如下
public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
其中postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。具体执行时期可以参考Spring中Bean的生命周期源码探究。
自定义BeanPostProcessor
查看BeanPostProcessor源码,可以看到它两个方法的参数都相同,其中第一个参数Object bean表示当前正在初始化的bean对象。此外两个方法都返回Object类型的实例,返回值既可以是将入参Object bean原封不动的返回出去,也可以对当前bean进行包装再返回。来看看下面的自定义BeanPostProcessor
/**
 * 后置处理器:初始化前后进行处理工作
 * 需要将后置处理器加入到容器中
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..."+beanName+"..."+bean);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..."+beanName+"..."+bean);
        return bean;
    }
}
Spring容器中加入MyBeanPostProcessor之后,针对容器中每个创建的Bean对象(Spring自身创建的Bean和应用程序创建的Bean),都会回调postProcessBeforeInitialization和postProcessAfterInitialization方法。
执行原理
BeanPostProcessor的执行是定义在容器的刷新过程中,容器刷新对象具体的方法为:AbstractApplicationContext.refresh()。
在refresh方法执行的调用栈中会去调用AbstractAutowireCapableBeanFactory.doCreateBean()方法,该方法节选源码如下
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    invokeInitMethods(beanName, wrappedBean, mbd);
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}
看到在调用初始化方法前后会分别调用applyBeanPostProcessorsBeforeInitialization()和applyBeanPostProcessorsAfterInitialization()。applyBeanPostProcessorsBeforeInitialization()方法的源码如下
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {
    Object result = existingBean;
    //获取所有的BeanPostProcessor进行遍历
    for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
        result = beanProcessor.postProcessBeforeInitialization(result, beanName);
        if (result == null) {
            return result;
        }
    }
    return result;
}
可以看到其逻辑为遍历得到容器中所有的BeanPostProcessor,然后一次执行postProcessBeforeInitialization,一但返回null,就跳出for循环不执行后面的BeanPostProcessor.postProcessorsBeforeInitialization()。也就是说如果返回的是null那么我们通过getBean方法将得不到目标Bean。applyBeanPostProcessorsBeforeInitialization()方法的逻辑和上面一致,就是将循环执行的beanProcessor.postProcessBeforeInitialization()替换成beanProcessor.postProcessAfterInitialization()
Spring底层的很多功能特性都是借助BeanPostProcessor的子类来实现。
常见BeanPostProcessor分析
下图是debug过程中,ApplicationContext对象中的包含的BeanPostProcessor。具体包含哪些BeanPostProcessor和具体应用程序相关,除了下标3中的MyBeanPostProcessor为自定义的BeanPostProcessor,其余均为Spring自带的BeanPostProcessor。

下面来分析一下ApplicationContextAwareProcessor和AutowiredAnnotationProcessor的执行原理。
ApplicationContextAwareProcessor
ApplicationContextAwareProcessor后置处理器的作用是,当应用程序定义的Bean实现ApplicationContextAware接口时注入ApplicationContext对象。
@Component
public class Car implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    public Car(){
        System.out.println("car instance...");
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("ApplicationContextAware...setApplicationContext()");
        this.applicationContext = applicationContext;
    }
}
那Car是如何通过实现ApplicationContextAware接口就能获得ApplicationContext对象呢?答案是通过ApplicationContextAwareProcessor后置处理器来实现,我们来看看ApplicationContextAwareProcessor的源码
class ApplicationContextAwareProcessor implements BeanPostProcessor {
    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;
    /**
     * Create a new ApplicationContextAwareProcessor for the given context.
     */
    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }
    @Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;
        // 这里bean是Car,它实现了ApplicationContextAware接口
        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            invokeAwareInterfaces(bean);
        }
        return bean;
    }
    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof EnvironmentAware) {
                ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
            }
            if (bean instanceof EmbeddedValueResolverAware) {
                ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
            }
            if (bean instanceof ResourceLoaderAware) {
                ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
            }
            if (bean instanceof ApplicationEventPublisherAware) {
                ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
            }
            if (bean instanceof MessageSourceAware) {
                ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
            }
            if (bean instanceof ApplicationContextAware) {
                // 会执行这里回调car重写的setApplicationContext方法,然后将this.applicationContext注入给Car
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
InitDestroyAnnotationBeanPostProcessor
InitDestroyAnnotationBeanPostProcessor后置处理器是用来处理自定义的初始化方法和销毁方法。Spring中提供了3种自定义初始化和销毁方法:
- 通过@Bean指定init-method和destroy-method属性
- Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑);
- @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法@PreDestroy:在容器销毁bean之前通知我们进行清理工作
InitDestroyAnnotationBeanPostProcessor的作用就是让第3种方式生效。先看看如何使用@PostConstruct和@PreDestroy注解。
@Component
public class Car {
    public Car(){
        System.out.println("car instance...");
    }
    /**
     * 自定义的初始化方法
     */
    @PostConstruct
    public void init(){
        System.out.println("car ... init...");
    }
    /**
     * 自定义的销毁方法
     */
    @PreDestroy
    public void detory(){
        System.out.println("car ... detory...");
    }
}
InitDestroyAnnotationBeanPostProcessor会在Bean创建的时候通过反射的方式查找包含@PostConstruct和@PreDestroy注解的方法,然后再通过反射执行方法。我们来看看InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()的源码
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 获取bean的metadata
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
    try {
        // 执行@PostConstruct指定的init方法
        metadata.invokeInitMethods(bean, beanName);
    }
    catch (InvocationTargetException ex) {
        throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
    }
    return bean;
}
metadata中已经解析出initMethods和destroyMethods,其具体内容如下。

metadata.invokeInitMethods(bean, beanName);就是根据反射执行init方法。
InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    //实例化Bean之前调用
    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
    //实例化Bean之后调用
    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
    //设置Bean对象中的某个属性时调用
    PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
}
这两个接口的功能基本类似,不过要注意InstantiationAwareBeanPostProcessor和BeanPostProcessor的方法名区别。InstantiationAwareBeanPostProcessor中是Instantiation, 而BeanPostProcessor是Initialization。
BeanPostProcessor详解的更多相关文章
- Spring中的BeanPostProcessor详解
		Spring中的BeanPostProcessor详解 概述 BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初 ... 
- 简单SSM配置详解
		SSM:spring+springMVC+Mybatis 学习网友的http://www.cnblogs.com/invban/p/5133257.html,并对其进行了详细的解说. 源码下载:htt ... 
- [转载] 多图详解Spring框架的设计理念与设计模式
		转载自http://developer.51cto.com/art/201006/205212_all.htm Spring作为现在最优秀的框架之一,已被广泛的使用,51CTO也曾经针对Spring框 ... 
- 10分钟详解Spring全家桶7大知识点
		Spring框架自2002年诞生以来一直备受开发者青睐,它包括SpringMVC.SpringBoot.Spring Cloud.Spring Cloud Dataflow等解决方案.有人亲切的称之为 ... 
- spring事务详解(三)源码详解
		系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ... 
- SpringBoot27 JDK动态代理详解、获取指定的类类型、动态注册Bean、接口调用框架
		1 JDK动态代理详解 静态代理.JDK动态代理.Cglib动态代理的简单实现方式和区别请参见我的另外一篇博文. 1.1 JDK代理的基本步骤 >通过实现InvocationHandler接口来 ... 
- [转载]Spring配置文件详解一:
		原文地址:与base-package="com.xx">Spring配置文件详解一:<context:annotation-config/>与<contex ... 
- Spring MVC配置文件的三个常用配置详解
		转自:http://www.cnblogs.com/benwu/articles/5162614.html Spring MVC项目中通常会有二个配置文件,sprng-servlet.xml和appl ... 
- Spring中的注入方式  和使用的注解   详解
		注解:http://www.cnblogs.com/liangxiaofeng/p/6390868.html 注入方式:http://www.cnblogs.com/java-class/p/4727 ... 
随机推荐
- CAP原理与最终一致性 强一致性 弱一致性
			CAP原理中,有三个要素: 一致性(Consistency) 可用性(Availability) 分区容忍性(Partition tolerance) CAP原理指的是,这三个要素最多只能同时实现两点 ... 
- php类知识点滴---类的实例化,构造函数,继承初步
			实例化类----黑科技用法,通过字符串来实例化 class coach { public function __construct() { echo "欢迎光临北武堂"." ... 
- Java-UploadHelper工具类
			/** * 上传文件类 */ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java. ... 
- web 9个令人震惊的WebGL示例
			20个使用WebGL和Three.js实现的网页场景 https://www.open-open.com/news/view/9d8136 20个使用WebGL和Three.js实现的网页场景 htt ... 
- Servlet中关于路径的小结
			URL(统一 资源定位符).URI(统一资源标识符)都是由资源路径和资源名称组成. 访问路径按照路径是否可以独立完成资源准确定位的判别标准,可以将访问路径分为绝对路径与相对路径. 关系:绝对路径 ... 
- 如何制作纯净的U盘启动盘
			1.去下载**WinPE工具箱**U盘启动盘制作工具 下载地址:http://www.wepe.com.cn/download.html 
- 微信小程序开发入门教程(一)---hello world
			由于无法备案网站,前期做了个微信小程序(开发版)就搁置了,几乎忘了开发过程.现在重新梳理,做个记录. 一.最基本的小程序前端例子hello 1.下载安装 微信开发者工具 官网: https://d ... 
- jsp+上传组件+文件夹+文件
			上次遇到这样一个问题,客户上传高清视频(1G以上)的时候上传失败. 一开始以为是session过期或者文件大小受系统限制,导致的错误.查看了系统的配置文件没有看到文件大小限制,web.xml中sees ... 
- HZOJ 20190719 那一天我们许下约定(dp+组合数)
			这个题目背景真的是让我想起了当年... 不说了,言归正传,这题,一眼看去30分暴力还是很好拿的,但我因为考试时的心态问题没有处理好细节爆了零. 30分暴力的普遍思路的复杂度应该是$O(nmd)$的,但 ... 
- 一、基本的bash shell命令(基于Ubuntu实现)
			一.基本的bash shell命令(基于Ubuntu实现) /etc/passwd文件包含了所有系统用户账户列表以及每个用户的基本配置信息. man命令 在想要查找的工具的名称前输入man命令,就可以 ... 
