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)。