SpringBoot 系列-Bean 的生命周期与扩展
本篇基于 SpringBoot 2.2.2.RELEASE 版本,Spring 各个版本之间多少存在一些差异,不过主流程基本相同;大家在阅读过程中需关注这点。
继续承接上一篇 SpringBoot 系列-启动过程分析,本篇围绕一个 bean 的生命周期,对 bean 进行一些修改和扩展。本篇将涉及到以下主要内容:
- 阅读之前
- BeanDefinition 解析时机和过程
- BeanFactoryPostProcessor 对 BeanDefinition 的修改
- 通过监听 ApplicationEnvironmentPreparedEvent 事件修改属性值
- @Value 注入 & @Autowired 注入
- Bean 的实例化过程
- 总结
阅读之前
下面是本篇文章的“主人公” TestBeanService ,定义如下:
public class TestBeanService {
/**
* 依赖注入
*/
@Autowired
private InjectBeanService injectBeanService;
/**
* 属性注入
*/
@Value("${spring.application.name}")
private String appName;
public String test() {
return injectBeanService.testInject();
}
}
TestBeanService 里面包括两个属性,一个是 injectBeanService ,另外一个是 appName,分别通过 @Autowired 和 @Value 注入值。本篇最终希望完成的目标是能够完成了解 Bean 属性注入的过程,以及 Bean 的实例化过程;除此之外,从 Spring 扩展的角度,来对 BeanFactoryPostProcess、BeanPostProcess、ApplicationListener、InitializingBean 以及 initMethod 的执行时机和作用进行分析。
TestBeanService 被解析成 BeanDifinition 的时机与过程
Spring 容器刷新流程非常复杂,当我们想 debug BeanDifinition 加载过程时可能没法很快找到入口,这里可以直接面向 BeanDifinition 的最终去向来 debug。我们知道 BeanFactory 接口本身是不具体注册 BeanDifinition 能力的,这个能力是由 BeanDefinitionRegistry 接口提供。那么就看下 BeanDefinitionRegistry 的 registerBeanDefinition 方法有几个具体的实现,然后在这几个实现出打上断点,执行找到具体的处理入口。
我们将断点打在 DefaultListableBeanFactory#registerBeanDefinition 这个方法入口处,debug 模式运行工程,可以看到断点进入时的情况如下图所示:
image这里通过执行堆栈逆向找到 BeanDifinition 的加载入口是容器刷新阶段的 invokeBeanFactoryPostProcessors 方法;这里就详细分析下 testBeanService 这个 beandifition 是怎么被注册到容器中的。
invokeBeanFactoryPostProcessors 执行过程分析
invokeBeanFactoryPostProcessors 这个方法实现非常长,但是基本处理过程很简单,存在很多重复的步骤。为了方便理解整个过程,这里还是有必要贴一下代码,代码中会详细标注所做的事情是什么,这个过程是构建 BeanFactory 非常重要一步。掌握这个过程,就可以随意玩转 BeanFactoryPostProcessor 了。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
// 当前 beanFactory 是否是 BeanDefinitionRegistry 类型
// 只有是 BeanDefinitionRegistry 类型,才具备注册 beanDefinition 的能力
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 普通的 BeanFactoryPostProcessor 集合
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// BeanDefinitionRegistryPostProcessor 类型处理器集合
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 这里 beanFactoryPostProcessors 是在 SharedMetadataReaderFactoryContextInitializer 中加进来的,是 Spring 自己的处理器
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// 如果是 BeanDefinitionRegistryPostProcessor 类型,就加到 registryProcessors
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
// 执行 BeanDefinitionRegistryPostProcessor 后置处理
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 否则就放到 regularPostProcessors
regularPostProcessors.add(postProcessor);
}
}
// 不要在这里初始化 FactoryBeans:需要保留所有未初始化的常规bean,以使 beanFacotryPostProcessor 对其处理!
// 分离实现 PriorityOrdered,Ordered和其余优先级的 BeanDefinitionRegistryPostProcessor。
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,调用实现 PriorityOrdered 的 BeanDefinitionRegistryPostProcessors。
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 遍历 BeanDefinitionRegistryPostProcessors
for (String ppName : postProcessorNames) {
// 只处理实现 PriorityOrdered 接口的 BeanDefinitionRegistryPostProcessor
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 符合上述条件的 BeanDefinitionRegistryPostProcessor 放到 currentRegistryProcessors 中,供后面使用
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 标记当前 postProcessor 已经处理过了
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 调用 BeanDefinitionRegistryPostProcessor 后置处理器
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 接下来,调用实现 Ordered的BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 最后,调用所有其他 BeanDefinitionRegistryPostProcessor,直到不再出现(保证全部处理完)。
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 现在,调用到目前为止已处理的所有处理器的 postProcessBeanFactory 回调。
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// 调用在上下文实例中注册的工厂处理器。就是前面提到的 SharedMetadataReaderFactoryContextInitializer 中注册的
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 这里再次拿到所有的 BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 同样将实现 PriorityOrdered、Order 和普通的 BeanFactoryPostProcessor 分离开
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 跳过-已在上述第一阶段处理过
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,调用实现PriorityOrdered的BeanFactoryPostProcessors。
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 优先执行实现 PriorityOrdered 接口的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 接下来,调用实现Ordered的BeanFactoryPostProcessors。
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
// 执行实现 Ordered 接口的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后,调用所有其他 BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
// 执行其他没有实现任何优先级接口的 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// 清除缓存的合并 beanDefinition,因为后处理器可能已经修改了原始元数据
beanFactory.clearMetadataCache();
}
上面代码段中大体就是,先处理 BeanDefinitionRegistryPostProcessor 类型的 BeanFactoryPostProcessor ,然后再处理普通的 BeanFactoryPostProcessor;在这里处理过程中,会根据一些排序规则来调整各个 BeanFactoryPostProcessor 的执行顺序。
这里先处理 BeanDefinitionRegistryPostProcessor 类型的 BeanFactoryPostProcessor 是一定的,因为需要在这个阶段去注册 BeanDefinition。在 classpath 下的所有 BeanDefinition 都被注册之后,再执行普通 BeanFactoryPostProcessor 的后置回调,这样就可以覆盖所有的 BeanDefinition。
invokeBeanDefinitionRegistryPostProcessors 执行过程分析
在第一次调用 invokeBeanDefinitionRegistryPostProcessors 时,当前的 BeanDefinitionRegistryPostProcessor 只有一个,就是 org.springframework.context.annotation.ConfigurationClassPostProcessor 。
在 ConfigurationClassPostProcessor 类中,会解析 @Configuration、@ComponentScan、@ComponentScans、@Import 等注解。ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor 接口,而 BeanDefinitionRegistryPostProcessor 接口继承了 BeanFactoryPostProcessor 接口,所以 ConfigurationClassPostProcessor 中需要重写 postProcessBeanDefinitionRegistry() 方法和 postProcessBeanFactory() 方法。而 ConfigurationClassPostProcessor 类的作用就是通过这两个方法去实现的。更多细节可以参考 ConfigurationClassPostProcessor源码解析 这篇文章,写的非常 nice。
invokeBeanDefinitionRegistryPostProcessors 处理的核心过程如下:
- 1、ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry:BeanDefinition 触发加载的入口
- 2、ConfigurationClassPostProcessor#processConfigBeanDefinitions:解析配置类,在此处会解析配置类上的注解(ComponentScan扫描出的类,@Import注册的类,以及@Bean方法定义的类)
- 3、ComponentScanAnnotationParser#parse:根据注解的属性值来过滤加载 classpath 下的 beanDefinition(默认条件就是 basePackages,默认的 basePackages 为当前启动类的根包)
- 4、ClassPathBeanDefinitionScanner#doScan:处理 basePackages 下所以的 beanDefinition,被打了 @Service、@Compoment 等注解的类都会被解析到
- 5、DefaultListableBeanFactory#registerBeanDefinition:将 beanDefinition 注册到 BeanFactory 中(beanDefinitionMap 中)
那么到这里 TestBeanService 的 BeanDefinition 就被注册到 BeanFactory 中了。
BeanFactoryPostProcessor 对 BeanDefinition 的修改
在本篇文章所对应的案例工程中,也实现了一个 BeanFactoryPostProcessor ,没有实现任何排序接口。这个 TestBeanServiceBeanFactoryPostProcessor 的作用是将原来的 TestBeanService 修改为 ProxyTestBeanService。代码如下:
public class TestBeanServiceBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 根据类型拿到所有的 beanNames
Iterable<String> beanNames = getBeanNames(beanFactory, TestBeanService.class);
// 这里因为只有一个 TestBeanService ,所以只处理第一个
beanNames.forEach(beanName -> {
System.out.println("begin to execute BeanFactoryPostProcessor...");
BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) beanFactory;
// 先从工程中拿到原始 beanDefinition
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
// 这里构建一个新的 BeanDefinition,类型为 ProxyTestBeanService,ProxyTestBeanService 是 TestBeanService 的子类
RootBeanDefinition proxy = new RootBeanDefinition(ProxyTestBeanService.class);
// 这里设置指定的initMethod
proxy.setInitMethodName(beanDefinition.getInitMethodName());
// 设置一些属性
proxy.setPropertyValues(beanDefinition.getPropertyValues());
proxy.setPrimary(beanDefinition.isPrimary());
proxy.setRole(BeanDefinition.ROLE_APPLICATION);
// 将原始 beanDefinition 移除掉
beanDefinitionRegistry.removeBeanDefinition(beanName);
// 将代理的新的 beanDefinition 注册进去
beanDefinitionRegistry.registerBeanDefinition(beanName,proxy);
System.out.println("current bean type is : " + proxy.getBeanClass().getTypeName());
return;
});
}
}
在 invokeBeanFactoryPostProcessors 执行过程分析中已经分析了 BeanFactoryPostProcessor 执行的时机和过程,这里不再赘述。TestBeanServiceBeanFactoryPostProcessor 的作用就是先将原始的 TestBeanService 的 Beandefinition 从容器中移除掉,然后构建一个 ProxyTestBeanService 的 Beandefinition,然后注册到容器中,beanName 没有变,所以通过 BeanFactoryPostProcessor 可以修改最原始的 Bean 信息,也可以通过 BeanFactoryPostProcessor 来动态注册一个新的 Bean。
通过监听 ApplicationEnvironmentPreparedEvent 事件修改属性值
上面完成了对 TestBeanService 的 BeanDefinition 的修改,将 TestBeanService 对象换成了 ProxyTestBeanService。前面提到 TestBeanService 中有两个需要注入的值,一个是通过 @Autowired 注入,一个是通过 @Value 注入,先来看 @Value 注入。@Value 注入的值来自 Enviroment,这里关于 Enviroment 和配置解析及构建不多说,本篇中关注的是如何将 @Value 注入的值改变掉。
ApplicationEnvironmentPreparedEvent 事件是在环境准备完成时发送的事件,此时 Enviroment 已经准备好,可以随时为容器刷新提供环境变量支持。那么既然此时容器中的 Enviroment 对象已经 ready ,说明配置的 application.properties、系统参数等均已经被解析好了,而此时目标 Bean 还没有被刷新,其内部需要被注入的属性值还没有被注入,那么此时就可以通过监听这个事件,来对 Enviroment 中已经准备好的值进行修改,以改变实际被注入的值。代码如下:
public class ChangeAppNameListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
// 获取原始 spring.application.name 的值
String applicationName = environment.getProperty("spring.application.name");
System.out.println("origin applicationName is : " + applicationName);
// 修改 spring.application.name
Properties props = new Properties();
props.put("spring.application.name", "updateAppName");
environment.getPropertySources().addFirst(new PropertiesPropertySource("decrypted_properties", props));
applicationName = environment.getProperty("spring.application.name");
System.out.println("updated applicationName is : " + applicationName);
}
}
@Value 注入 & @Autowired 注入
在 Spring 中,无论是 @Value 注入还是 @Autowired 注入,都是由 AutowiredAnnotationBeanPostProcessor 这个后置处理器处理的。
在很多开源的框架中,其内部自定义的注解也大都是通过 BeanPostProcessor 这个后置处理器来处理的。
AutowiredAnnotationBeanPostProcessor 中有个 AutowiredFieldElement 内部类,这个内部类的作用就是注入目标 bean 的属性值的。这里就包括 @Value 的注入和 @Autowired 注入。
Bean 属性注入发生的时机
容器刷新及属性注入调用堆栈如下:
image从堆栈看出,在容器刷新的最后阶段,会通过 finishBeanFactoryInitialization 这个方法实例化所有剩余的(非延迟初始化)单例 bean;这个过程就是绝大多数 bean 实例化的过程。这个过程中会涉及到以下两个比较重要的点:1、BeanPostProcessor 处理,2、依赖注入。从上面其实也可以看出,依赖注入的发生就是通过 BeanPostProcessor 处理完成的。下图为遍历所有目标属性,依次注入属性的过程:
imageBean 属性注入发生的过程
这里以 @Autowired 注入为例,@Value 注入和 @Autowired 注入过程基本是一样的。@Autowired 注入相比于 @Value 注入,会涉及到初始化另外一个 Bean 的过程。
// 构建一个依赖描述符对象
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
// 设置包含此依赖项的具体类
desc.setContainingClass(bean.getClass());
// 初始化一个注入的 beanName 集合,用于后面注册到容器中
// 这里实际上只有一个,如果有多个实例 bean 存在,则需要通过 Qualifier 指定了
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 解析依赖,依赖注入
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
// 抛出注入失败异常
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
// 注册依赖的 bean
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
// 判断容器中是否存在此依赖 bean,并且校验 bean 的类型是否匹配
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
// 缓存注入值
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
// 没有找到 依赖bean 实例,且 required 为 false
this.cachedFieldValue = null;
}
this.cached = true;
}
}
// value 为解析到的属性值,如果不为空,则通过反射设置给目标 Bean,完成属性的注入
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
属性注入发生在 populateBean(填充 Bean)的过程,在 Bean 属性填充完成之后就是 Bean 的实例化过程。
Bean 的实例化过程
这里截取 AbstractAutowireCapableBeanFactory#doCreateBean 方法中的一小段代码,来承接上下文:
// 初始化bean实例。
Object exposedObject = bean;
try {
// 填充 Bean
populateBean(beanName, mbd, instanceWrapper);
// 实例化 Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// 省略异常处理
}
这里通过代码就很好的和上一小节的内容关联起来了,即填充 Bean -> 实例化 Bean 。在 Bean 的实例化阶段会涉及到两个比较重要的扩展:1、BeanPostProcessor,2、InitializingBean。
BeanPostProcessor 的处理时机
BeanPostProcessor 有两个抽象方法,一个是实例化之前调用,一个是实例化之后调用。InitializingBean 接口只有一个 afterPropertiesSet 方法,afterPropertiesSet 方法的执行介于实例化之前实例化之后调用之间。BeanPostProcessor 的处理时机是在调用 initializeBean 方法中触发的,下面为 initializeBean 方法中的部分代码片段:
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 实例化之前调用
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用 InitializingBean 和指定的 init-method 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 实例化之后调用
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
这里的 bean 对象实际上已经是完整的 bean 了,postProcessBeforeInitialization 和 postProcessAfterInitialization 是相对于是否执行 InitializingBean 的 afterPropertiesSet 和执行 Bean 指定的 initMethod 方法而言的。
使用 BeanPostProcessor 修改 Bean
从 initializeBean 方法中可以看出,了,postProcessBeforeInitialization 和 postProcessAfterInitialization 两处回调返回放回的是 wrappedBean,也就意味着我们可以在这两个方法中对容器中的原始 Bean 做一些处理,比如代理一层原始的 Bean,或者修改 Bean 中的一些属性等。
在案例工程中提供了一个 TestBeanServiceProcessor ,其作用是对 TestBeanService 类型的 Bean 做一层代理,使得在执行 TestBeanService 中方法的前后做一些埋点。
// TestBeanServiceProcessor
public class TestBeanServiceProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 如果 bean 的类型是 TestBeanService,则将其包装成 TestBeanWrapperService 并返回
if (bean instanceof TestBeanService){
System.out.println("begin to execute postProcessBeforeInitialization.");
TestBeanWrapperService testBeanService = new TestBeanWrapperService((TestBeanService)bean);
return testBeanService;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof TestBeanService){
System.out.println("begin to execute postProcessAfterInitialization.");
}
return bean;
}
}
// 代理类 TestBeanWrapperService,注意这里代理类也应该是 TestBeanService 类型,否在是后面使用时就会找不到 Bean 实例
public class TestBeanWrapperService extends TestBeanService {
private final TestBeanService delegate;
public TestBeanWrapperService(TestBeanService delegate){
this.delegate = delegate;
}
/**
* 实现对 test 方法执行前后进行拦截
**/
@Override
public String test() {
try {
before();
return delegate.test();
} finally {
after();
}
}
private void before(){
System.out.println("before execute test.");
}
private void after(){
System.out.println("after execute test.");
}
}
使用 InitializingBean
如果一个 bean 集成了 InitializingBean 接口,那么就需要重写其 afterPropertiesSet 方法。这里感觉有点漏洞,afterPropertiesSet 动作其实早就完成了,另外因为 afterPropertiesSet 是在 postProcessAfterInitialization 方法之前调用,所以还是可以在 postProcessAfterInitialization 对属性做修改。实际使用过程中需要关注下这个点,一般情况下,我们会在 afterPropertiesSet 中做一些初始化动作,比如启动连接 Zookeeper。
public class TestBeanService implements InitializingBean {
// 省略其他代码
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("begin to execute afterPropertiesSet...");
}
}
指定 Bean 的 init-method 方法
init-method 方法只能通过 @Bean 或者 xml 方式指定,如果是使用 @Component 或者 @Service 注解标准的 Bean ,则可以通过 @PostConstruct 注解标注方法,对应的是 destroy-method 和 @PreDestroy 。
public class TestBeanService implements InitializingBean{
// 省略其他代码
// init 方法
public void init(){
System.out.println("begin to execute init...");
}
}
// 在自动配置类或者 xml 文件中指定 initMethod
@Bean(initMethod = "init")
public TestBeanService testBeanService(){
return new TestBeanService();
}
总结
本篇围绕 TestBeanService 这个 Bean 展开,对其生命周期,及其生命周期各个阶段扩展点进行了介绍,包括修改注入的属性值、修改其 BeanDefinition、修改 Bean 实例等等,从扩展点的视角来洞悉一个 Bean 的生命周期。
BeanFactoryPostProcessor 对于 init-method 的影响
因为 init-method 这个点是后面想起来加上去的,在实际测试过程中,发现 TestBeanService 中指定的 init 方法没有被执行(正常情况下是在 afterPropertiesSet 之后就会执行的);对于这个 TestBeanService 在案例工程中有两处对其进行了修改,一个是修改其 BeanDefinition ,一个是修改 其 Bean 实例;最终拿到的 bean 的类型是 TestBeanWrapperService,在此之前 Bean 的类型是 ProxyTestBeanService ,无论是TestBeanWrapperService 还是 ProxyTestBeanService 都是 TestBeanService 的子类,init 方法又是 public 的,所以从这个角度来看,不可能不生效。所以基本可以排除因为访问权限问题导致。最后 debug 下面代码发现,mbd.getInitMethodName() 返回的是 null, mbd 是 RootBeanDefinition;
PS: BeanDefinition 中 getInitMethodName 方法是在 Spring 5.1 版本之后才有的,之前版本都是 在 AbstractBeanDefinition 这个抽象类中定义。
if (mbd != null && bean.getClass() != NullBean.class) {
// 从当前 bean 的 BeanDefinition 对象中获取 initMethod 方法名
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
问题出在这里,在 TestBeanServiceBeanFactoryPostProcessor 处理时,没有将原始 BeanDefinition 的 initMethod 给新的 ProxyTestBeanService,所以导致后面所有基于此实例化的 bean 的 BeanDefinition 都没有 initMethod 方法。在TestBeanServiceBeanFactoryPostProcessor#postProcessBeanFactory 方法中补充设置 InitMethodName 之后问题解决。
// 这里设置指定的initMethod
proxy.setInitMethodName(beanDefinition.getInitMethodName());