简单分析BeanPostProcessor
1. 什么是BeanPostProcessor
BeanPostProcessor是一个接口,有两个方法,分别是:Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException 和 Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
Spring Bean的生命周期中,在为Bean实例化,装配好属性后,会调用上下文中所有的BeanPostProcessor对象的两个方法为其初始化;
2. 一个小例子
分别创建三个类,分别是接口类、接口类的实现类,和BeanPostProcessor的实现类。
package com.khlin.my.test; public interface WelcomeService { void welcome();
}
package com.khlin.my.test; import org.springframework.beans.factory.InitializingBean; public class WelcomeServiceImpl implements WelcomeService, InitializingBean { public void init() {
System.out.println("init.");
} public void welcome() {
System.out.println("Welcome to Spring.");
} public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet.");
}
}
package com.khlin.my.test; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; public class LoginProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("login successfully.");
return o;
} public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("logout successfully.");
return o;
}
}
在applicationContext.xml里实例化对应的Bean.
<bean id="welcomeService" class="com.khlin.my.test.WelcomeServiceImpl" init-method="init"/>
<bean id="loginProcessor" class="com.khlin.my.test.LoginProcessor"/>
再写一个启动类
package com.khlin.my.test; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class IOCTest { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("context 启动成功");
WelcomeService messageService = context.getBean(WelcomeService.class);
messageService.welcome();
}
}
启动main方法,输出如下:
调用顺序分别为:
BeanPostProcessor的postProcessBeforeInitialization
InitializingBean的afterPropertiesSet
init方法
BeanPostProcessor的postProcessAfterInitialization
3. 实现原理
我们来看一下Spring启动一个上下文的时候,都做了啥。这里不作详细的源码解读。
可以看到上下文ApplicationContext持有一个BeanFactory。在第一个红框,将所有的BeanPostProcessor注册到BeanFactory。
调试代码,可以看到注册后保存在BeanFactory的beanPostProcessors集合里。
再来看第二个红框,finishBeanFactoryInitialization() 这个方法会对Bean进行初始化。
在AbstractAutowireCapableBeanFactory这个类的protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd)方法里,可以看到invokeInitMethods方法被夹在BeanPostProcessor两个方法的中间。
在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中,会遍历所有注册的BeanBeanProcessor并调用方法。
每个BeanPostProcessor可以返回处理后的对象,如果返回null,会导致遍历中断,可能有些BeanPostProcessor无法处理,这点要注意。
InitMethod有两种方式,一种是在配置文件中加上init-method属性并指定对应的方法,另一种是实现InitializingBean接口的afterPropertiesSet()方法。
可以看到是优先调用afterPropertiesSet()方法,再调用init-method指定的方法,这与我们的输出顺序一致。
4. 总结
Spring Bean的生命周期,在初始化阶段的调用顺序为:
BeanPostProcessor的postProcessBeforeInitialization
InitializingBean的afterPropertiesSet
init方法
BeanPostProcessor的postProcessAfterInitialization
如果有一个BeanPostProcessor返回null,会导致遍历的中断,可能有些BeanPostProcessor无法调用。因此一般不返回null.
简单分析BeanPostProcessor的更多相关文章
- AbstractRoutingDataSource 实现动态数据源切换原理简单分析
AbstractRoutingDataSource 实现动态数据源切换原理简单分析 写在前面,项目中用到了动态数据源切换,记录一下其运行机制. 代码展示 下面列出一些关键代码,后续分析会用到 数据配置 ...
- 简单分析JavaScript中的面向对象
初学JavaScript的时候有人会认为JavaScript不是一门面向对象的语言,因为JS是没有类的概念的,但是这并不代表JavaScript没有对象的存在,而且JavaScript也提供了其它的方 ...
- CSipSimple 简单分析
简介 CSipSimple是一款可以在android手机上使用的支持sip的网络电话软件,可以在上面设置使用callda网络电话.连接使用方式最好是使用wifi,或者3g这样上网速度快,打起电话来效果 ...
- C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析与解决方法
对于C#中异常:“The type initializer to throw an exception(类型初始值设定项引发异常)”的简单分析,目前本人分析两种情况,如下: 情况一: 借鉴麒麟.NET ...
- 透过byte数组简单分析Java序列化、Kryo、ProtoBuf序列化
序列化在高性能网络编程.分布式系统开发中是举足轻重的之前有用过Java序列化.ProtocolBuffer等,在这篇文章这里中简单分析序列化后的byte数组观察各种序列化的差异与性能,这里主要分析Ja ...
- 简单分析Java的HashMap.entrySet()的实现
关于Java的HashMap.entrySet(),文档是这样描述的:这个方法返回一个Set,这个Set是HashMap的视图,对Map的操作会在Set上反映出来,反过来也是.原文是 Returns ...
- Ffmpeg解析media容器过程/ ffmpeg 源代码简单分析 : av_read_frame()
ffmpeg 源代码简单分析 : av_read_frame() http://blog.csdn.net/leixiaohua1020/article/details/12678577 ffmpeg ...
- FFmpeg的HEVC解码器源码简单分析:解析器(Parser)部分
===================================================== HEVC源码分析文章列表: [解码 -libavcodec HEVC 解码器] FFmpeg ...
- FFmpeg资料来源简单分析:libswscale的sws_getContext()
===================================================== FFmpeg库函数的源代码的分析文章: [骨架] FFmpeg源码结构图 - 解码 FFmp ...
随机推荐
- Java的Lambda表达式
Java的Lambda表达式 1. 什么是Lambda表达式 简单的说,Lambda表达式就是匿名方法.Lambda表达式让程序员能够使用更加简洁的代码,但是同样也使代码的可读性比较差. Lambda ...
- matplotlib画图报错This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
之前用以下代码将实验结果用matplotlib show出来 plt.plot(np.arange(len(aver_reward_list)), aver_reward_list) plt.ylab ...
- 黑马vue---46、vue使用过渡类名实现动画
黑马vue---46.vue使用过渡类名实现动画 一.总结 一句话总结: vue动画的过渡类名的时间点中没有设置样式的话就是默认的样式 使用 transition 元素,把 需要被动画控制的元素,包裹 ...
- Sublime Text 全局搜索Ctrl+Shift+F快捷键不能用
Sublime Text 全局搜索Ctrl+Shift+F快捷键不能用 和微软输入法的简繁体切换冲突了,关闭输入法的简繁体切换快捷键就好了! 文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢 ...
- Android——coredump解析
撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/46916869本文来自 [jscese]的博客! coredump文件生成前文And ...
- Swift 字面量
所谓字面量,就是指像特定的数字,字符串或者是布尔值这样,能够直接了当地指出自己的类型并为变量进行赋值的值.比如在下面: let aNumber = //整型字面量 let aString = &quo ...
- Python 数据库的Connection、Cursor两大对象
Python 数据库的Connection.Cursor两大对象 pymysql是Python中操作MySQL的模块,其使用方法和py2的MySQLdb几乎相同. Python 数据库图解流程 Con ...
- 【如何设置IIS程序池的回收时间,才能最大程度的减少对用户的影响?】
作为.Net开发人员,其实对IIS的应用程序池知之甚少,前段时间被问到一个问题: 对于互联网web应用,如何在用户毫无感知的情况下回收程序池?(对用户产生最小的影响) 简单理解IIS应用程序池 应用程 ...
- WPF 设置TextBox为空时,背景为文字提示。
<TextBox FontSize="> <TextBox.Resources> <VisualBrush x:Key="HelpBrush" ...
- ndroid如何监听开机广播和关机广播
需求描述:有些时候,我们需要我们的程序在开机后能自动运行,在系统即将关闭时,能写入一些记录到指定的文件里. 一.开机广播监听: Android系统启动完成后会发出启动完成广播(android.inte ...