[Spring]影响Spring Bean生命周期的BeanPostProcessor

前言

Spring中使用了许多BeanPostPorcessor来处理回调,在了解Spring Bean的生命周期时,会发现充斥着许多BeanPostProcessor的方法执行.了解这些Spring框架的BeanPostProcessor,来试图找到一些AOP有关的线索.
从整体的视角来看,Spring IoC支持以注解驱动的方式来创建与管理对象,那么Spring AOP是用来代理对象的,没有了对象,空谈Spring AOP是无意义的。在前面分析getBean的流程中,我们也找到了一些AOP的蛛丝马迹,下面我们从BeanPostcessor的角度来看看在Bean的生命周期中一些关键的后置处理器.

UML

UML
  • InstantiationAwareBeanPostProcessor: InstantiationAwareBeanPostProcessorBeanPostProcessor的子接口,主要是用于Spring框架内部使用

  • SmartInstantiationAwareBeanPostProcessor: 扩展InstantiationAwareBeanPostProcessor接口,添加了用于预测已处理bean的最终类型的回调、声明构造函数等.

  • AbstractAutoProxyCreator: 使用AOP代理包装每个合格的bean,并在调用bean本身之前委派给指定的拦截器

  • MergedBeanDefinitionPostProcessor: 主要处理合并BeanDefinition的回调,其中一个经典的接口为postProcessMergedBeanDefinition,用来找到被Spring支持的注解所标记的元数据。

  • AutowiredAnnotationBeanPostProcessor: 提供对Spring内部定义的注解支持:@Autowired@Value@Lookup,同时也支持@Inject注解来声明注入

  • CommonAnnotationBeanPostProcessor: 提供对JSR注解的支持,常见的注解有@PostConstruct@PreDestroy@Resource.

  • ApplicationContextAwareProcessor:ApplicationContext传递给实现EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAware接口的bean。

  • DestructionAwareBeanPostProcessor: 用于添加破坏前的回调。
    典型的用法是在特定的bean类型上调用自定义销毁回调,并与相应的初始化回调匹配。

InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,主要是用于Spring框架内部使用,它有3个回调方法,通常用于抑制特定目标Bean的默认实例化,例如,创建具有特殊TargetSource的代理(池目标,延迟初始化目标等),或实施其他注入策略,例如字段注入:

  • postProcessBeforeInstantiation

在实例化目标bean(doCreateBean)之前应用此BeanPostProcessor。返回的Bean对象可以是代替目标Bean使用的代理,从而有效地抑制了目标Bean的默认实例化。
如果此方法返回一个非null对象,则bean创建过程将被短路。可以应用自已配置BeanPostProcessors的postProcessAfterInitialization回调来进一步处理。

  • postProcessAfterInstantiation

通过构造函数或工厂方法在实例化bean之后但在发生Spring属性填充(通过显式属性或自动装配)之前执行操作。
这是在Spring的自动装配开始之前对给定的bean实例执行自定义字段注入的理想回调。
默认实现返回true。

  • postProcessProperties

在beanFactory将其作为getBean的返回值前,对给定的属性值(比如被Spring框架的注解标注的成员)进行后处理,无需使用属性描述符(property descriptors)。
这个关键的方法便是populateBean中的@Autowired注解解析入口.

SmartInstantiationAwareBeanPostProcessor

Spring框架内部使用的专用接口,扩展了InstantiationAwareBeanPostProcessor接口,在整个Spring Bean的生命周期中,会经常与该接口打交道。

  1. predictBeanType:
    预测从此处理器的postProcessBeforeInstantiation回调最终返回的bean的类型。
    默认实现返回null。
    Bean在经过postProcessBeforeInstantiation处理后也许返回了代理类,那么此处即提前声明好代理后的对象类型.
  2. determineCandidateConstructors
    声明给定bean所要应用的候选构造函数。
    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#determineConstructorsFromBeanPostProcessors中使用了该方法用于Bean的实例化过程中推断构造函数,如果能从SmartInstantiationAwareBeanPostProcessor中获取到构造函数数组,那么直接使用该构造函数数组进行对象实例化.
  3. getEarlyBeanReference
    提前暴露引用,用于解决循环依赖问题.

MergedBeanDefinitionPostProcessor

AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor都实现了此接口,用于查找被Spring所支持的注解所标记的元数据. 在doCreateBean中,会调用applyMergedBeanDefinitionPostProcessors对此后置处理器进行统一激活.
下面贴一下经典的案例:

  • AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition
    @Override
    /**
     * InjectionMetadata-内部类,用于管理注入元数据。不适用于直接在应用程序中使用。
     */
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 扫描当前Class是否有被@Autowired、@Value标记的成员变量,最终封装到InjectionMetadata中
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        // 将Spring容器需要用默认策略注入的 element 保存到 checkedElements 中
        metadata.checkConfigMembers(beanDefinition);
    }

ApplicationContextAwareProcessor

主要用于处理实现了Aware接口的回调.重写了BeanPostProcessorpostProcessBeforeInitialization方法.在AbstractAutowireCapableBeanFactory#initializeBean中,工厂会先执行invokeAwareMethods来激活BeanNameAwareBeanClassLoaderAwareBeanFactoryAware,其他的Aware接口交由此后置处理器进行激活.

    @Override
    @Nullable
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        AccessControlContext acc = null;

        if (System.getSecurityManager() != null &&
                (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
                        bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
                        bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
            acc = this.applicationContext.getBeanFactory().getAccessControlContext();
        }

        if (acc != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareInterfaces(bean);
                return null;
            }, acc);
        }
        else {
            invokeAwareInterfaces(bean);
        }

        return bean;
    }
    
    // 激活实现了Aware的接口: EnvironmentAware、EmbeddedValueResolverAware  
    // ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware  
    // ApplicationContextAware
    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) {
                ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
            }
        }
    }

DestructionAwareBeanPostProcessor

在销毁Bean前执行Bean所声明的自定义销毁方法.
假设一个Bean实现了DisposableBean,那么在Spring Bean初始化的时候就会注册销毁方法,在Spring对Bean进行销毁的时候,通过此后置处理器进行统一激活。

流程图

以下是今天文章所讲的BeanPostProcessor对Spring Bean生命周期的管理.

1
2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容