【spring源码分析】IOC容器初始化——查漏补缺(三)
前言:本文分析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容器初始化——查漏补缺(三)的更多相关文章
- 【spring源码分析】IOC容器初始化——查漏补缺(一)
前言:在[spring源码分析]IOC容器初始化(十一)中提到了初始化bean的三个步骤: 激活Aware方法. 后置处理器应用(before/after). 激活自定义的init方法. 这里我们就来 ...
- 【spring源码分析】IOC容器初始化——查漏补缺(五)
前言:我们知道在Spring中经常使用配置文件的形式对进行属性的赋值,那配置文件的值是怎么赋值到属性上的呢,本文将对其进行分析. 首先了解一个类:PropertySourcesPlaceholderC ...
- 【spring源码分析】IOC容器初始化——查漏补缺(二)
前言:在[spring源码分析]IOC容器初始化(八)中多次提到了前置处理与后置处理,本篇文章针对此问题进行分析.Spring对前置处理或后置处理主要通过BeanPostProcessor进行实现. ...
- 【spring源码分析】IOC容器初始化——查漏补缺(四)
前言:在前几篇查漏补缺中,其实我们已经涉及到bean生命周期了,本篇内容进行详细分析. 首先看bean实例化过程: 分析: bean实例化开始后 注入对象属性后(前面IOC初始化十几篇文章). 检查激 ...
- SPRING源码分析:IOC容器
在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求: ...
- Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...
- spring源码分析---IOC(1)
我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...
- spring 源码之 ioc 容器的初始化和注入简图
IoC最核心就是两个过程:IoC容器初始化和IoC依赖注入,下面通过简单的图示来表述其中的关键过程:
- Spring源码阅读-IoC容器解析
目录 Spring IoC容器 ApplicationContext设计解析 BeanFactory ListableBeanFactory HierarchicalBeanFactory Messa ...
随机推荐
- SVN 问题解决之 The XML response contains invalid XML
公司几个同事的SVN更新时出现了The XML response contains invalid XML报错 经Google得到一个线索,可能和Http请求有关. 想起之前项目改过一次网络请求方式, ...
- Zookeeper 安装及集群配置注意点
Zookeeper在ubuntu下安装及集群搭建,关于集群搭建,网上很多文章 可以参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-z ...
- 用<audio>标签打造一个属于自己的HTML5音乐播放器
上一章节,我们刚刚讲了<video>标签,今晚,我们讲的是<audio>标签,这两个东东除了表示的内容不一样以外,其他的特性相似的地方真的太多了,属性和用法几乎一样,也就说,如 ...
- div上中下布局中间自适应
需求1: 头尾固定高度,中间自适应 1.上部(header)Div高度固定100px,宽度100%: 2.下部(footer)Div高度固定100px,宽度100%: 3.中部(middle)DIV高 ...
- drunk_admin_hacking_challenge靶机之旅?
注: 只是记录本人玩的时候发现的新奇点 如果你也想玩且看了这篇文章还是不会,请联系gg 靶机下载地址 https://www.vulnhub.com/entry/drunk-admin-web-h ...
- win server服务器 关闭危险端口 135,137,138,139,445的方法
Windows默认开放135.137.138.139和445五个端口,都与文件共享和打印机共享有关的,若机器连接网络后会在用户不知道的情况下泄露本机部分信息,这样会给用户带来一部分危险,所以我们在工作 ...
- Python asyncio 模块
Python 3.4 asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLo ...
- 3.Vue过滤器
1.概念: Vue.js 允许你自定义过滤器,可被用作一些常见文本的格式化,过滤器可以用在两个地方:mustache 插值和 v-bind 表达式.过滤器应该被添加在 JavaScript 表达式的尾 ...
- IIS搭建ASP站点
1. 进入控制面板悬着打开或者关闭Windows功能. 2. 手工选择需要的功能进行安装. 3. 打开运行Internet信息服务(IIS)管理工具. 4. 展开左侧栏看到“Default Web S ...
- post和get的在测试眼里的区别大概就是post比get安全吧……
get将请求数据放在url中,而post将请求数据放在request body中 http://www.cnblogs.com/logsharing/p/8448446.html