一文读不懂BeanPostProcessor源码+实例详解

1 缘起

学习Spring容器以回调方式进行通知Bean时,
发现Aware源码中如下图(位置:org.springframework.beans.factory.Aware)
有这样一段描述:处理必须确定完成,如 org.springframework.beans.factory.config.BeanPostProcessor,
于是进入BeanPostProcessor,发现并没有“直接关系”,(其实是Bean生命周期的先后关系)
但是,我对BeanPostProcessor还没有掌握,
因此,探索了一下,分享如下。

在这里插入图片描述

2 BeanPostProcessor

工厂Hook。允许自定义修改实例化的Bean,如检查标记接口或者通过代理包装Bean。
典型应用:post-processor通过标记接口或者实现postProcessBeforeInitialization填充Bean,
post-processors通过代理包装Bean需要实现postProcessAfterInitialization。

  • 【关于注册】
    ApplicationContext可以自动检测自身BeanPostProcessor的bean列表,
    将post-processor应用到随后创建的任意Bean中。
    普通BeanFactory允许对post-processor进行编程注册,
    并将post-processor应用到通过BeanFactory创建的Bean。
  • 【关于Order】
    ApplicationContext自动检测BeanPostProcessor bean列表,
    并根据org.springframework.core.PriorityOrdered和org.springframework.core.Ordered进行排序。
    相反,BeanPostProcessor bean列表通过BeanFactory编程注册会以注册顺序应用,
    任何通过实现PriorityOrdered或者Ordered接口排序语义表达式则会忽略编程注册顺序。
    BeanPostProcessor bean列表不会考虑@Order注解。

位置:org.springframework.beans.factory.config.BeanPostProcessor
在这里插入图片描述

2.1 postProcessorBeforeInitialization

Bean初始化之前回调该BeanPostProcessor方法,如InitialzingBean的afterPropertiesSet或者自定义init方法。
Bean已经填充属性,返回的bean实例或许是包装的Bean。

在这里插入图片描述

2.2 postProcessorAfterInitialization

初始化Bean之后回调该BeanPostProcessor方法,如InitialzingBean的afterPropertiesSet或者自定义init方法。
对于FactoryBean,这个回调由FactroyBean实例和FactoryBean创建的对象调用。
post-processor可以通过instanceof决定是否应用到FactoryBean或者FactoryBean创建的对象。
在这里插入图片描述

2.3 处理流程

由上面的分析可知,post-processor处理Bean初始化前和初始化后,完成的流程如下图所示。
BeanPostProcessor是Hook设计方式,
什么是hook,查了一下,核心理念:将一系列监听与取消监听放置在一起,可以不关心组件生命周期,
只需要关心外部依赖的变化,这里关心Bean初始化状态。
在这里插入图片描述

3 测试

了解了BeanPostProcessor的处理流程,下面演示Bean初始化前后的执行流程。

3.1 初始化Bean

这是通过实现InitializingBean接口,重写afterPropertiesSet方法初始化Bean,
BeanPostProcessor也说了初始化前样例有InitializingBean的afterPropertiesSet方法。

package com.monkey.tutorial.common.mybean;

import com.monkey.tutorial.modules.user.vo.BaseUserVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

/**
 * InitializingBean初始化Bean.
 *
 * @author xindaqi
 * @date 2021-08-31 11:41
 */
@Component
public class InitializingTest implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(InitializingTest.class);

    public BaseUserVO baseUserVO;

    /**
     * 初始化Bean属性.
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("\n>>>>>>>>>>InitializingBean初始化BaseUserVO:START");
        this.baseUserVO = new BaseUserVO("123", "InitializingBean", "male");
        logger.info("\n>>>>>>>>>>InitializingBean初始化BaseUserVO:END");
    }
}

3.2 实现BeanPostProcessor

实现BeanPostProcessor接口,自定义Bean初始化之前和初始化之后操作,
添加@Configuration注解,
通过instanceof确定是否对指定的Bean进行相关的处理,实现样例如下。

package com.monkey.tutorial.common.config.bean_process;

import com.monkey.tutorial.modules.user.service.IUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;

/**
 * BeanPostProcessor测试.
 *
 * @author xindaqi
 * @date 2022-06-13 17:28
 */
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {

    private static final Logger logger = LoggerFactory.getLogger(MyBeanPostProcessor.class);

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        logger.info(">>>>>>>>>Before bean post process:{}", beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        logger.info(">>>>>>>>>After bean post processor:{}", beanName);
        if (bean instanceof IUserService) {
            logger.info(">>>>>>>>>User service:");
        }
        return bean;
    }
}

3.3 结果

启动SpringBoot,控制台日志如下图所示。
由图可知,Bean InitializingTest初始化之前日志:>>>>>>>>Before bean post process:initializingTest
Bean初始化:STRRT,END
Bean初始化之后:>>>>>>>>After bean post process:initializingTest
执行顺序符合:Bean初始化前->Bean初始化->Bean初始化后。
在这里插入图片描述

4 小结

核心:
(1)BeanPostProcessor是hook设计方式,封装监听与取消监听操作,即Bean实例化前和Bean实例化后;
(2)执行顺序:Bean初始化前(postProcessorBeforeInitializing)->Bean初始化->Bean初始化后(postProcessorAfterInitializing)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值