# 【死磕 Spring】—— IoC 之深入分析 InitializingBean 和 init-method
**本文主要基于 Spring 5.0.6.RELEASE**
摘要: 原创出处 http://cmsblogs.com/?p=3340 「小明哥」,谢谢!
作为「小明哥」的忠实读者,「老艿艿」略作修改,记录在理解过程中,参考的资料。
------
Spring 在 bean 初始化时进行三个检测扩展,也就是说我们可以对 bean 进行三个不同的定制化处理,前面两篇博客 [《【死磕 Spring】—— IoC 之深入分析 Aware 接口》](http://svip.iocoder.cn/Spring/IoC-Aware-interface) 和 [《【死磕 Spring】—— IoC 之深入分析 BeanPostProcessor》](http://svip.iocoder.cn/Spring/IoC-BeanPostProcessor) 已经分析了 Aware 接口族和 BeanPostProcessor 接口,这篇分析 InitializingBean 接口和 `init-method` 方法。
# 1. InitializingBean
Spring 的 `org.springframework.beans.factory.InitializingBean` 接口,为 bean 提供了定义初始化方法的方式,它仅包含了一个方法:`#afterPropertiesSet()` 。代码如下:
```
public interface InitializingBean {
/**
* 该方法在 BeanFactory 设置完了所有属性之后被调用
* 该方法允许 bean 实例设置了所有 bean 属性时执行初始化工作,如果该过程出现了错误则需要抛出异常
*
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
*
This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
```
Spring 在完成实例化后,设置完所有属性,进行 “Aware 接口” 和 “BeanPostProcessor 前置处理”之后,会接着检测当前 bean 对象是否实现了 InitializingBean 接口。如果是,则会调用其 `#afterPropertiesSet()` 方法,进一步调整 bean 实例对象的状态。
## 1.1 示例
```
public class InitializingBeanTest implements InitializingBean {
private String name;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBeanTest initializing...");
this.name = "chenssy 2 号";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
配置项如下:
```
```
测试代码如下:
```
InitializingBeanTest test = (InitializingBeanTest) factory.getBean("initializingBeanTest");
System.out.println("name :" + test.getName());
```
执行结果如下:
[](http://static.iocoder.cn/4b96bfb7f25ce1550985b7463d232121)
在这个示例中,改变了 InitializingBeanTest 示例的 `name` 属性,也就是说 在 `#afterPropertiesSet()` 方法中,我们是可以改变 bean 的属性的,这相当于 Spring 容器又给我们提供了一种可以改变 bean 实例对象的方法。
## 1.2 invokeInitMethods
上面提到 bean 初始化阶段( `#initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)` 方法), Spring 容器会主动检查当前 bean 是否已经实现了 InitializingBean 接口,如果实现了,则会掉用其 `#afterPropertiesSet()` 方法。这个主动检查、调用的动作是由 `#invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)` 方法来完成的。代码如下:
```
// AbstractAutowireCapableBeanFactory.java
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 首先会检查是否是 InitializingBean ,如果是的话需要调用 afterPropertiesSet()
boolean isInitializingBean = (bean instanceof InitializingBean);
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