前言:本文分析InitializingBean和init-method方法,其实该知识点在AbstractAutowireCapableBeanFactory#initializeBean方法中有所提及,这里对其进行详细分析。


InitializingBean

InitializingBean是一个接口,它只包含一个afterPropertiesSet方法:

 public interface InitializingBean {

     /**
* 该方法在BeanFactory设置完了所有的属性之后被调用<br/>
* 该方法允许bean实例设置了所有bean属性时执行初始化工作,如果该过程出现了错误,则需要抛出异常<br/>
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>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实例对象的状态。

InitializingBean示例

 public class UserDefinedInitializingBean implements InitializingBean {

     private String msg;

     public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet......");
this.msg = "修改了msg,msg=hello initializingBean!!!!!!";
}
}

进行如下配置:

 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean"
p:msg="i am msg!!!"/>

测试:

 @Test
public void initializingBeanTest() {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:com/dev/config/initializingbean/initializingbean.xml");
UserDefinedInitializingBean initializingBean = context.getBean(UserDefinedInitializingBean.class);
System.out.println(initializingBean.getMsg());
}

运行结果如下:

从运行结果来看,msg属性被我们修改了,在afterPropertiesSet方法中,这相当于Spring又提供给我们一种可以改变bean实例对象的方法。

invokeInitMethods

InitializingBean的afterPropertiesSet方法就是在invokeInitMethods方法中被执行的。

AbstractAutowireCapableBeanFactory#invokeInitMethods:

 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.isDebugEnabled()) {
logger.debug("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) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 激活用户自定义的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}

分析:

  • 首先检查当前bean是否实现了InitializingBean接口,如果实现了,则调用其afterPropertiesSet方法。
  • 然后再检查是否指定了init-method,如果指定了init-method方法,则通过反射进行调用。

init-method

对init-method进行示例,只需根据上面示例进行一点调整即可。

 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean"
p:msg="i am msg!!!" init-method="initMethod"/>

在UserDefinedInitializingBean中增加如下代码:

 public void initMethod() {
System.out.println("通过init-method方法对msg属性进行修改");
this.msg = "修改了msg,msg=hello init-method!!!!!!";
}

运行结果如下:

从结果上可以看到init-method方法是在afterPropertiesSet方法之后,并且达到了同样的效果,对代码无侵入性。

分析到这里其实已经把bean的生命周期都总结出来,下篇文章进行具体总结,这里想来看本篇小结。

总结

从invokeInitMethods方法中,我们知道init-method指定的方法会在afterPropertiesSet方法后执行,如果afterPropertiesSet方法执行过程中出现异常,init-method方法是不会执行的。使用init-method使其对业务代码的侵入降低,虽然init-method是基于xml配置文件的,但我们也可以通过@PostConstruct注解的形式来进行替换。

至此InitializingBean和init-method已分析完毕,对于DisposableBean和destroy-method与init相似,这里不再进行赘述。


by Shawn Chen,2019.05.05,下午。

【spring源码分析】IOC容器初始化——查漏补缺(三)的更多相关文章

  1. 【spring源码分析】IOC容器初始化——查漏补缺(一)

    前言:在[spring源码分析]IOC容器初始化(十一)中提到了初始化bean的三个步骤: 激活Aware方法. 后置处理器应用(before/after). 激活自定义的init方法. 这里我们就来 ...

  2. 【spring源码分析】IOC容器初始化——查漏补缺(五)

    前言:我们知道在Spring中经常使用配置文件的形式对进行属性的赋值,那配置文件的值是怎么赋值到属性上的呢,本文将对其进行分析. 首先了解一个类:PropertySourcesPlaceholderC ...

  3. 【spring源码分析】IOC容器初始化——查漏补缺(二)

    前言:在[spring源码分析]IOC容器初始化(八)中多次提到了前置处理与后置处理,本篇文章针对此问题进行分析.Spring对前置处理或后置处理主要通过BeanPostProcessor进行实现. ...

  4. 【spring源码分析】IOC容器初始化——查漏补缺(四)

    前言:在前几篇查漏补缺中,其实我们已经涉及到bean生命周期了,本篇内容进行详细分析. 首先看bean实例化过程: 分析: bean实例化开始后 注入对象属性后(前面IOC初始化十几篇文章). 检查激 ...

  5. SPRING源码分析:IOC容器

    在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求: ...

  6. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  7. spring源码分析---IOC(1)

    我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...

  8. spring 源码之 ioc 容器的初始化和注入简图

    IoC最核心就是两个过程:IoC容器初始化和IoC依赖注入,下面通过简单的图示来表述其中的关键过程:

  9. Spring源码阅读-IoC容器解析

    目录 Spring IoC容器 ApplicationContext设计解析 BeanFactory ListableBeanFactory HierarchicalBeanFactory Messa ...

随机推荐

  1. SVN 问题解决之 The XML response contains invalid XML

    公司几个同事的SVN更新时出现了The XML response contains invalid XML报错 经Google得到一个线索,可能和Http请求有关. 想起之前项目改过一次网络请求方式, ...

  2. Zookeeper 安装及集群配置注意点

    Zookeeper在ubuntu下安装及集群搭建,关于集群搭建,网上很多文章 可以参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-z ...

  3. 用<audio>标签打造一个属于自己的HTML5音乐播放器

    上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...

  4. div上中下布局中间自适应

    需求1: 头尾固定高度,中间自适应 1.上部(header)Div高度固定100px,宽度100%: 2.下部(footer)Div高度固定100px,宽度100%: 3.中部(middle)DIV高 ...

  5. drunk_admin_hacking_challenge靶机之旅?

    注:  只是记录本人玩的时候发现的新奇点  如果你也想玩且看了这篇文章还是不会,请联系gg 靶机下载地址 https://www.vulnhub.com/entry/drunk-admin-web-h ...

  6. win server服务器 关闭危险端口 135,137,138,139,445的方法

    Windows默认开放135.137.138.139和445五个端口,都与文件共享和打印机共享有关的,若机器连接网络后会在用户不知道的情况下泄露本机部分信息,这样会给用户带来一部分危险,所以我们在工作 ...

  7. Python asyncio 模块

    Python 3.4 asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLo ...

  8. 3.Vue过滤器

    1.概念: Vue.js 允许你自定义过滤器,可被用作一些常见文本的格式化,过滤器可以用在两个地方:mustache 插值和 v-bind 表达式.过滤器应该被添加在 JavaScript 表达式的尾 ...

  9. IIS搭建ASP站点

    1. 进入控制面板悬着打开或者关闭Windows功能. 2. 手工选择需要的功能进行安装. 3. 打开运行Internet信息服务(IIS)管理工具. 4. 展开左侧栏看到“Default Web S ...

  10. post和get的在测试眼里的区别大概就是post比get安全吧……

    get将请求数据放在url中,而post将请求数据放在request body中 http://www.cnblogs.com/logsharing/p/8448446.html