glmapper

SpringBoot 系列-Bean 的生命周期与扩展

字数统计: 4.6k阅读时长: 19 min
2019/12/14 Share

本篇基于 SpringBoot 2.2.2.RELEASE 版本,Spring 各个版本之间多少存在一些差异,不过主流程基本相同;大家在阅读过程中需关注这点。

继续承接上一篇 SpringBoot 系列-启动过程分析,本篇围绕一个 bean 的生命周期,对 bean 进行一些修改和扩展。本篇将涉及到以下主要内容:

阅读之前

下面是本篇文章的“主人公” TestBeanService ,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 模式运行工程,可以看到断点进入时的情况如下图所示:

这里通过执行堆栈逆向找到 BeanDifinition 的加载入口是容器刷新阶段的 invokeBeanFactoryPostProcessors 方法;这里就详细分析下 testBeanService 这个 beandifition 是怎么被注册到容器中的。

invokeBeanFactoryPostProcessors 执行过程分析

invokeBeanFactoryPostProcessors 这个方法实现非常长,但是基本处理过程很简单,存在很多重复的步骤。为了方便理解整个过程,这里还是有必要贴一下代码,代码中会详细标注所做的事情是什么,这个过程是构建 BeanFactory 非常重要一步。掌握这个过程,就可以随意玩转 BeanFactoryPostProcessor 了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 中已经准备好的值进行修改,以改变实际被注入的值。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 属性注入发生的时机

容器刷新及属性注入调用堆栈如下:

从堆栈看出,在容器刷新的最后阶段,会通过 finishBeanFactoryInitialization 这个方法实例化所有剩余的(非延迟初始化)单例 bean;这个过程就是绝大多数 bean 实例化的过程。这个过程中会涉及到以下两个比较重要的点:1、BeanPostProcessor 处理,2、依赖注入。从上面其实也可以看出,依赖注入的发生就是通过 BeanPostProcessor 处理完成的。下图为遍历所有目标属性,依次注入属性的过程:

Bean 属性注入发生的过程

这里以 @Autowired 注入为例,@Value 注入和 @Autowired 注入过程基本是一样的。@Autowired 注入相比于 @Value 注入,会涉及到初始化另外一个 Bean 的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 构建一个依赖描述符对象
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 方法中的一小段代码,来承接上下文:

1
2
3
4
5
6
7
8
9
10
11
// 初始化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 方法中的部分代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 中方法的前后做一些埋点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 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。

1
2
3
4
5
6
7
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 。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 这个抽象类中定义。

1
2
3
4
5
6
7
8
9
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 之后问题解决。

1
2
// 这里设置指定的initMethod
proxy.setInitMethodName(beanDefinition.getInitMethodName());

附:案例工程地址及参考

原文作者:GuoLei Song

原文链接:http://www.glmapper.com/2019/12/14/springboot-series-bean-life/

发表日期:December 14th 2019, 11:24:14 am

更新日期:December 15th 2019, 11:43:58 pm

版权声明:转载请注明出处

CATALOG
  1. 1. 阅读之前
  2. 2. TestBeanService 被解析成 BeanDifinition 的时机与过程
    1. 2.1. invokeBeanFactoryPostProcessors 执行过程分析
    2. 2.2. invokeBeanDefinitionRegistryPostProcessors 执行过程分析
  3. 3. BeanFactoryPostProcessor 对 BeanDefinition 的修改
  4. 4. 通过监听 ApplicationEnvironmentPreparedEvent 事件修改属性值
  5. 5. @Value 注入 & @Autowired 注入
    1. 5.1. Bean 属性注入发生的时机
    2. 5.2. Bean 属性注入发生的过程
  6. 6. Bean 的实例化过程
    1. 6.1. BeanPostProcessor 的处理时机
    2. 6.2. 使用 BeanPostProcessor 修改 Bean
    3. 6.3. 使用 InitializingBean
    4. 6.4. 指定 Bean 的 init-method 方法
  7. 7. 总结
    1. 7.1. BeanFactoryPostProcessor 对于 init-method 的影响
    2. 7.2. 附:案例工程地址及参考