Spring框架提供了多种方式控制bean初始化的过程,开发者可以自定义初始化的逻辑。

有如下几种自定义bean初始化逻辑的方式:

  1. 使用@PostConstruct注解
  2. 自定义初始化方法,比如@Bean(initMethod = "method1")
  3. 实现InitializingBean接口的afterPropertiesSet()方法
  4. 实现SmartInitializingSingleton接口的afterSingletonsInstantiated()方法

这四种方式都可以用于自定义bean的初始化。但是每种方法执行的时机不太一样,通过Spring源码来给大家逐一介绍。

首先自定义一个bean,分别实现上述4中方式。

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
package com.ubuntuvim.spring.createbean;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;

import javax.annotation.PostConstruct;

/**
* 验证不同方式初始化回调的执行顺序:
* 0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法
* 1. 执行初始化回调@PostConstruct注解定义的方法
* 2. 执行初始化回调InitializingBean.afterPropertiesSet()方法
* 3. 执行初始化回调@Bean(initMethod = "beanInit")定义的方法
* 4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法
* 5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法,
* 此回调是在bean实例化和初始化完成之后执行的
*
* @Author: ubuntuvim
* @Date: 2020/10/18 上午1:16
*/
public class InitCallbackBean implements InitializingBean, SmartInitializingSingleton {

/**
* 如果一个类中多个方法都使用@PostConstruct注解声明,则会根据方法名按照字母升序顺序执行。
* 比如init()和afterPropertiesSet()都加了注解,那么先执行afterPropertiesSet()方法
*/
@PostConstruct
public void init() {
System.out.println("执行初始化回调@PostConstruct注解定义的方法");
}

@PostConstruct
public void init2() {
System.out.println("执行初始化回调@PostConstruct注解定义的方法init2()");
}

/**
* 如果用户在afterPropertiesSet()方法上也使用了@PostConstruct注解,此方法在后置处理器中会先被执行
* @see InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
* 然后在执行初始化回调接口InitializingBean时不会再次执行。
* @see AbstractAutowireCapableBeanFactory#invokeInitMethods(String, Object, RootBeanDefinition)
* 也就是说同时在回调接口InitializingBean上同时使用@PostConstruct注解只会执行一次,但是可以改变方法的执行时机,
* 比如本类中init()和afterPropertiesSet()都加了@PostConstruct注解,那么先执行afterPropertiesSet()方法,
* 如果afterPropertiesSet()方法不加@PostConstruct注解,那么会先执行init()方法,再执行afterProperties()方法。
* 因为@PostConstruct注解优先于回调接口InitializingBean执行
*
* 如果@Bean注解中自定义的方法也使用@PostConstruct注解声明,那么这个方法会重复执行。
* 1. 后置处理器处理@PostConstruct注解方法的时候执行一次,
* 2. 执行自定义的方法的时候也执行一次
*
* @Bean(initMethod = "afterPropertiesSet")
* 如果自定义的方法和InitializingBean的回调方法一致。
* afterPropertiesSet()方法会执行一次,只执行InitializingBean的回调,不会在执行自定义方法的回调。
* 原因可以看Spring源码,位置:
* @see AbstractAutowireCapableBeanFactory#invokeInitMethods(String, Object, RootBeanDefinition)
*
* @Bean(initMethod = "initBean")
* 如果自定义的方法也使用了@PostConstruct声明,那么initBean()会执行两次。
* 1. 后置处理器处理@PostConstruct注解方法的时候执行一次,
* 2. 执行自定义的方法的时候也执行一次
*
* 总结一句话,InitializingBean.afterPropertiesSet()方法只会执行一次。
* @PostConstruct 声明的方法都会执行,不管有几个,执行顺序按照方法名升序执行
*/
// @PostConstruct
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行初始化回调InitializingBean.afterPropertiesSet()方法");
}

@Override
public void afterSingletonsInstantiated() {
System.out.println("执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法");
}

@PostConstruct
private void beanInit() {
System.out.println("执行初始化回调@Bean(initMethod = \"beanInit\")定义的方法");
}
}

通过@Bean方式把此类注入到Spring容器中。

1
2
3
4
5
6
7
8
@ComponentScan
@Configuration
public class Config {
@Bean(initMethod = "beanInit")
public InitCallbackBean initCallbackBean() {
return new InitCallbackBean();
}
}

首先运行看结果是怎么样的。

1
2
3
4
5
6
执行初始化回调@PostConstruct注解定义的init方法
执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解
执行初始化回调@PostConstruct注解定义的方法init2()
执行初始化回调InitializingBean.afterPropertiesSet()方法
执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解
执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法

通过运行结果分析,可以看到使用@PostConstruct注解的方法会第一个执行,beanInit方法同时使用了@PostConstruct注解,并且同时在@Bean中也指定成bean自定义的初始化方法,所以这个方法执行了两次。如果同一个类中有个多个方法都使用了@PostConstruct注解,那么这些被注解的方法都会被执行,但是执行的顺序不一定是方法在类中的代码顺序。

做点好玩的事情,在afterPropertiesSet()方法上也使用@PostConstruct注解,再运行看看结果是怎么样,会不会执行两遍?

1
2
3
4
5
6
执行初始化回调@PostConstruct注解定义的init方法
执行初始化回调InitializingBean.afterPropertiesSet()方法
执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解
执行初始化回调@PostConstruct注解定义的方法init2()
执行初始化回调@Bean(initMethod = "beanInit")定义的方法,并且此方法也使用了@PostConstruct注解
执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法

这个就比较有意思了,可以看到afterPropertiesSet()方法只执行了一遍。

这几种初始化方法执行顺序是怎么设定的呢?为何使用@PostConstruct注解的方法可以执行多次,而afterPropertiesSet()方法却执行一次呢?
带这些疑问,我们阅读Spring源码,从源码中找答案。

不同初始化方式的执行时机

这些初始化方法都是在有bean实例之后执行的,我们可以大概的猜测到这些初始化回调应该是在Spring框架完成bean实例化,进行属性填充的时候执行的。

如果你对Spring框架bean的实例化、初始化不是很了解的请看之前的系列博客:https://www.toutiao.com/i6887194772914733571

直接打开如下类方法,

1
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

这个方法是Spring容器非常核心的方法,它处理了很多事情:单例实例化、填充属性、执行初始化回调、注册销毁回调方法。

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
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {

// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 从缓存中查询,如果是bean定义是一个bean工厂实例可以直接拿到。
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 普通bean,根据bean定义创建bean实例,并包装成BeanWrapper返回
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 获取经过jdk1.8的Optional类包装过的非空对象
final Object bean = instanceWrapper.getWrappedInstance();
// 获取bean的class类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// 执行后置处理器接口MergedBeanDefinitionPostProcessor,bean实例化之后,就可以通过反射获取到类或者属性上的注释信息
// 处理@Resource、@Autowired、@Value注解的定义信息,并把这些注解的定义信息放在缓存中。待后续属性填充的时候使用。
// 如果有则吧注解信息转换成AutowiredFieldElement对象或者AutowiredMethodElement对象或者ResourceElement对象
// 实现类有:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor等
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 单例bean && 允许循环依赖 && bean正在被创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
/**
* 执行后置处理器SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference()方法尝试获取一个早期的引用。
* 并加入的单例工厂缓存中
* @see DefaultSingletonBeanRegistry#addSingletonFactory(String, ObjectFactory)
* @see #getEarlyBeanReference
*/
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

// Initialize the bean instance.
// 初始化bean实例,填充属性,注入依赖(@Autowired,@Resource,@Value)注解的属性
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
/**
执行bean的初始化回调方法以及执行后置处理器的初始化方法,包括:
一,执行Aware接口 ,包括BeanFactoryAware,BeanClassLoaderAware,BeanNameAware
注意:ApplicationContext的注入是在另外一个后置处理器ApplicationContextAwareProcessor中执行。
二,执行bean初始化回调,包括:
0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法
1. 执行初始化回调@PostConstruct注解定义的方法
2. 执行初始化回调InitializingBean.afterPropertiesSet()方法
3. 执行初始化回调@Bean(initMethod = "beanInit")定义的初始化方法beanInit()
4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法
5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法
按照上述执行顺序执行
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 循环依赖检查
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}

// Register bean as disposable.
try {
/**
* 注册bean销毁回调方法,这个方法和前面的initializeBean()方法是对应的。通常情况下初始化方法和销毁方法是同时出现的。
* 比如回调DisposableBean接口的destroy()方法,需要注意的是这里只是注册,并不会执行销毁回调方法。
* 销毁方法的调用是在手动执行容器的关闭方法的时候:
* @see org.springframework.context.support.AbstractApplicationContext#close()
*
* @see AbstractBeanFactory#registerDisposableBeanIfNecessary(String, Object, RootBeanDefinition)
*/
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
/**
* 回到调用处:
* @see #createBean(String, RootBeanDefinition, Object[])
*/
return exposedObject;
}

其中initializeBean(beanName, exposedObject, mbd)这行是本次我们需要关注的,所有的初始化回调都是在这个方法中执行的。
进入这个方法的代码:

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
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* 本方法的作用有
* 一,执行Aware接口 ,包括BeanFactoryAware,BeanClassLoaderAware,BeanNameAware
* 注意:ApplicationContext的注入是在另外一个后置处理器ApplicationContextAwareProcessor中执行。
* 二,执行bean初始化回调,包括:
* 0. 执行初始化回调BeanPostProcessor.postProcessBeforeInitialization()方法
* 1. 执行初始化回调@PostConstruct注解定义的方法
* 2. 执行初始化回调InitializingBean.afterPropertiesSet()方法
* 3. 执行初始化回调@Bean(initMethod = "beanInit")定义的方法
* 4. 执行初始化回调BeanPostProcessor.postProcessAfterInitialization()方法
* 5. 执行初始化回调SmartInitializingSingleton.afterSingletonsInstantiated()方法
* 按照上述执行顺序执行
*
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
* 方法调用处:
* @see #doCreateBean(String, RootBeanDefinition, Object[])
*/
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 如果bean实现了XxxAware接口,则调用这些接口的setXxx()方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

/**
* 执行后置处理器的postProcessorBeforeInitialization()方法
* 这里会首先执行第一个初始化回调@PostConstruct声明的方法,是这个类实现的
* @see org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization
*/
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 执行InitializingBean接口和自定义的初始化方法(@Bean(initMethod = "beanInit"))
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
/**
* 执行后置处理器的postProcessorAfterInitialization()方法
*/
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
/**
* 完成各种初始化回调方法,回到调用处:
* @see #doCreateBean(String, RootBeanDefinition, Object[])
*/
return wrappedBean;
}

在此方法中就可以看到初始化回调的执行顺序,首先是applyBeanPostProcessorsBeforeInitialization()这个方法里面会执行@PostContruct注解的方法,是通过后置处理器实现的。

其次是invokeInitMethods()方法,这个方法内会执行的InitializingBean接口的afterPropertiesSet()方法,以及执行在@Bean注解中定义的初始化方法。

最后的是applyBeanPostProcessorsAfterInitialization()方法,这个方法会执行后置处理器接口SmartInitializingSingletonafterSingletonsInstantiated()方法。

到此解决了一个疑问,不同类型的回调的执行顺序就是在上述代码中设定的。

PostConstruct注解方法的执行

此注解执行的处理类是org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization

进入此方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 获取@PostConstruct注解定义的方法
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}

这个方法逻辑比较简单,findLifecycleMetadata()把使用了注解@PostConstruct定义的方法包装成LifecycleMetadata,然后在invokeInitMethods()方法中执行。这两个方法的最底层都是通过反射实现的。

回到前面的疑问,@PostConstruct注解的方法为何可以有多个?并且无法控制方法的执行顺序?

第二个疑问,进入findLifecycleMetadata()方法的实现就知道了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
// 通过反射获取到使用@PostConstruct注解的方法,并包装成LifecycleMetadata
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}

这个方法还不是真正实现的地方,还需要继续进入buildLifecycleMetadata()方法。

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
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}

List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;

do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

// 通过反射获取到目标类的方法列表,然后遍历这些方法判断是否有使用@PostConstruct注解
// 如果有则保存到currInitMethods
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});

initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);

return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}

在继续进入doWithLocalMethods()方法, 这个方法还做了一层封装。核心的方法实现在getDeclaredMethods(),这个方法里面最主要一句代码Method[] declaredMethods = clazz.getDeclaredMethods();,这行代码只要用过反射的应该很熟悉。直接通过class获取到类内部的所有方法(包括继承过来的方法)。clazz.getDeclaredMethods()方法返回的是一个数组,里面的元素没有提供排序的入口。所以最终执行的@PostConstruct注解的方法也不知道顺序。

1
2
3
4
5
6
7
8
9
10
11
12
public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
// 通过反射获取目标类内部的方法
Method[] methods = getDeclaredMethods(clazz, false);
for (Method method : methods) {
try {
mc.doWith(method);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
}
}
}

拿到所有注解的方法之后,直接通过for循环逐个执行。从入口一直到这里执行注解方法的过程中,没有对方法做任何的过滤,直接for循环遍历执行。所以同一个类是支持在多个方法上使用@PostConstruct注解,并且会把所有使用了注解的方法执行。

InitializingBean接口执行

@PostConstruct注解的方法执行完毕之后,回到initializeBean()方法中,继续往下执行invokeInitMethods()方法。这个方法中就会执行所有实现了InitializingBean接口的实现类。

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
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {

boolean isInitializingBean = (bean instanceof InitializingBean);
// 使用@PostConstruct定义的方法在解析bean定义时候会初始化到bean定义属性externallyManagedInitMethods里面
// 如果用户在afterPropertiesSet()方法上也使用了@PostConstruct注解则不会再执行。
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}

if (mbd != null && bean.getClass() != NullBean.class) {
// 获取自定义的初始化方法,比如@Bean(initMethod = "beanInit"),自定义的初始化方法就是beanInit()
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
// 排除自定义的初始化方法也是afterPropertiesSet()方法,避免重复执行
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
// 使用@PostConstruct定义的方法在解析bean定义时候会初始化到bean定义属性externallyManagedInitMethods里面
// 方式初始化方法重复执行,如果在前面执行@PostConstruct方法已经执行过同名方法则不再执行
// 另外,如果@Bean自定义的回调方法也是afterPropertiesSet()方法,
// 这里不会再次执行,因为在前面InitializingBean接口方法已经执行过
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

此方法的逻辑也很明了,分为两部分:前面部分就是判断当前bean是否实现了接口,如果是就直接执行接口的afterPropertiesSet()方法。

1
((InitializingBean) bean).afterPropertiesSet();    

但是在执行之前有一段校验逻辑mbd.isExternallyManagedInitMethod("afterPropertiesSet"),这一行代码就是用于判断,如果前面使用@PostConstruct注解声明的方法中已经包含了afterPropertiesSet则不会在执行这个方法。避免重复执行。这也就是为何演示例子中afterPropertiesSet()方法只会执行一遍的原因。并且是在执行@PostConstruct方法列表的时候就执行了。

这个方法的第二部分也同样有校验。在执行@Bean自定义的初始化方法之前也是先判断afterPropertiesSet()方法是否已经执行过。避免@Bean(initMethod = "afterPropertiesSet")这种情况导致方法重复执行。

@Bean中自定义的方法的执行详细逻辑就不贴代码了,最底层也是通过反射执行的。

好了,完成了@Bean自定义方法和InitializingBean接口方法的执行之后,接着回到initializeBean()方法中,继续往下执行applyBeanPostProcessorsAfterInitialization()方法,这个方法主要是执行后置处理器的postProcessAfterInitialization()方法的。和本篇主题无关,不过多解释。

afterSingletonsInstantiated()方法执行

最后就是SmartInitializingSingleton.afterSingletonsInstantiated()方法的执行,此方法的执行和前面的初始化回调不在一个地方,这个方法是在bean实例化完成,并且完成了属性填充之后。才执行的,代码位置在:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

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
/**
* 实例化所有除了Spring内部的单例(懒加载的、抽象类、非单例的除外)
*/
@Override
public void preInstantiateSingletons() throws BeansException {
// 省略与本篇无关代码

// =========================================================================
// 到此单例bean都已经实例化完毕,紧接着可以对实例对象做一些增强,通过BeanPostProcessor后置处理器增强

// Trigger post-initialization callback for all applicable beans...
// 判断是否有实现了SmartInittializingSingleton的实现类,通常是Spring内部的实现类,也是Spring提供的一个很重要的扩展点
// 初始化操作执行顺序:@PostConstruct是最先被执行的,然后是InitializingBean,最后是SmartInitializingSingleton
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
// bean实例化后调用bean的afterSingletonsInstantiated方法,用户可以实现SmartInitializingSingleton接口,
// 在所有bean实例化后做一些自定义的操作,比如重置实例的某些属性,但是要注意只能处理非懒加载的单例bean
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}

此处也是一个后置处理器,这个是Spring框架提供的一个对所有bean初始化的入口。前面的初始化回调都是针对某一个bean做得处理。这个是最大的不同之处。只要你实现了此接口方法afterSingletonsInstantiated(),所有的bean在初始化完成之后执行此方法逻辑。

好了,到此总算是把所有的初始化回调介绍完毕。你是否搞懂了呢??