详解Spring中的ApplicationListener和ContextRefreshedEvent
ApplicationListener和ContextRefreshedEvent一般都是成对出现的。最近在面试中问到了被面试者对于这两个的用法,面试者大多数被问懵了。可见基础知识的掌握程度。基于此本文将介绍它们的用法。
事件机制作为一种编程机制,在许多语言中都提供了支持。JAVA语言也不例外,java中的事件机制的参与者有3种角色:
- event object
- event source
- event listener
这三个角色的含义字面上很好解,它们就定义了事件机制的一个基本模型。作为一种常用的编程设计机制,许多开源框架的设计中都使用了事件机制。SpringFramework也不例外。
在IOC的容器的启动过程,当所有的bean都已经处理完成之后,spring ioc容器会有一个发布事件的动作。从 AbstractApplicationContext 的源码中就可以看出:
protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
// 业余草:www.xttblog.com
// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}
这样,当ioc容器加载处理完相应的bean之后,也给我们提供了一个机会(先有InitializingBean,后有ApplicationListener<ContextRefreshedEvent>),可以去做一些自己想做的事。其实这也就是spring ioc容器给提供的一个扩展的地方。我们可以这样使用这个扩展机制。
org.springframework.context.ApplicationEvent
org.springframework.context.ApplicationListener
一个最简单的方式就是,让我们的bean实现ApplicationListener接口,这样当发布事件时,spring的ioc容器就会以容器的实例对象作为事件源类,并从中找到事件的监听者,此时ApplicationListener接口实例中的onApplicationEvent(E event)方法就会被调用,我们的逻辑代码就会写在此处。这样我们的目的就达到了。但这也带来一个思考,有人可能会想,这样的代码我们也可以通过实现spring的InitializingBean接口来实现啊,也会被spring容器去自动调用,但是大家应该想到,如果我们现在想做的事,是必须要等到所有的bean都被处理完成之后再进行,此时InitializingBean接口的实现就不合适了,所以需要深刻理解事件机制的应用场合。
曾经有一位同事利用 ApplicationListener,重复加载了好几次 xml 配置文件。所以基础知识一定要掌握。
下面是一个完整的例子:
public class ApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
private static Logger _log = LoggerFactory.getLogger(ApplicationContextListener.class);
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
// root application context
if(null == contextRefreshedEvent.getApplicationContext().getParent()) {
_log.debug(">>>>> spring初始化完毕 <<<<<");
// spring初始化完毕后,通过反射调用所有使用BaseService注解的initMapper方法
Map<String, Object> baseServices =
contextRefreshedEvent.getApplicationContext().getBeansWithAnnotation(BaseService.class);
for(Object service : baseServices.values()) {
_log.debug(">>>>> {}.initMapper()", service.getClass().getName());
try {
Method initMapper = service.getClass().getMethod("initMapper");
initMapper.invoke(service);
} catch (Exception e) {
_log.error("初始化BaseService的initMapper方法异常", e);
e.printStackTrace();
}
}
// 系统入口初始化
Map<String, BaseInterface> baseInterfaceBeans =
contextRefreshedEvent.getApplicationContext().getBeansOfType(BaseInterface.class);
for(Object service : baseInterfaceBeans.values()) {
_log.debug(">>>>> {}.init()", service.getClass().getName());
try {
Method init = service.getClass().getMethod("init");
init.invoke(service);
} catch (Exception e) {
_log.error("初始化BaseInterface的init方法异常", e);
e.printStackTrace();
}
}
}
}
}
以上就是ApplicationListener和ContextRefreshedEvent的相关用法。
详解Spring中的ApplicationListener和ContextRefreshedEvent的更多相关文章
- 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)
用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是 ...
- 使用IDEA详解Spring中依赖注入的类型(上)
使用IDEA详解Spring中依赖注入的类型(上) 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件 ...
- 详解Spring中Bean的作用域与生命周期
摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我 ...
- 【Spring】详解Spring中Bean的加载
之前写过bean的解析,这篇来讲讲bean的加载,加载要比bean的解析复杂些,该文之前在小编原文中有发表过,要看原文的可以直接点击原文查看,从之前的例子开始,Spring中加载一个bean的方式: ...
- 详解Spring中的Profile
前言 由于在项目中使用Maven打包部署的时候,经常由于配置参数过多(比如Nginx服务器的信息.ZooKeeper的信息.数据库连接.Redis服务器地址等),导致实际现网的配置参数与测试服务器参数 ...
- 详解Spring中的CharacterEncodingFilter
在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...
- 详解Spring中的CharacterEncodingFilter--forceEncoding为true在java代码中设置失效--html设置编码无效
在项目中有很多让人头疼的问题,其中,编码问题位列其一,那么在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?下面我们来看看Spring框架给我们提供过滤器CharacterEncodin ...
- applicationContext.xml详解 spring+mybatis+struts
今天给大家详细解释一项关于Spring的applicationContext.xml文件,这对于初学者来说,应该是很有帮助的, 以下是详解Spring的applicationContext.xml文件 ...
- 【转】详解spring 每个jar的作用
spring.jar 是包含有完整发布模块的单个jar 包.但是不包括mock.jar, aspects.jar, spring-portlet.jar, and spring-hibernate2. ...
随机推荐
- Python1 简介及安装、基础
Python介绍 Python是面向对象,高级语言,解释,动态和多用途编程语言.Python易于学习,而且功能强大,功能多样的脚本语言使其对应用程序开发具有吸引力. Python的语法和动态类型具有其 ...
- 《剑指offer》旋转数组中的最小数字
本题来自<剑指offer> 旋转数组中的最小数字 题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例 ...
- laravel Blade 模板引擎
与视图文件紧密关联的就是模板代码,我们在视图文件中通过模板代码和 HTML 代码结合实现视图的渲染.和很多其他后端语言不同,PHP 本身就可以当做模板语言来使用,但是这种方式有很多缺点,比如安全上的隐 ...
- Vue中使用Vue.component定义两个全局组件,用单标签应用组件时,只显示一个组件的问题和 $emit的使用。
解决方法: 定义了两个 Vue.component 在 el 中使用的时候要用 双标签, 用单表标签的时候,只会显示第个 组件间 这样写只显示 welcome-button 组件 <welcom ...
- shell 判断目录是否存在
判断/data/www/logs/wos_log/crontab_log是否, 如果不存在则新建 if [ ! -d "/data/www/logs/wos_log/crontab_log& ...
- 抓包工具Charles Proxy v4.1.1破解版下载
移动开发抓包工具Charles Proxy破解版下载 下载Charles Proxy版本,http://charles.iiilab.com/或 https://www.charlesproxy.co ...
- 饮冰三年-人工智能-Python-13Python基础之运算符与数据类型
1:算数运算符 + - * / ** % // 2: 成员运算符 in not in name = """张三""" if "张& ...
- mysql 5.7 安装
linux(CentOS6.7) 环境Mysql 5.7.17安装教程分享给大家,供大家参考,具体内容如下: 1系统约定 安装文件下载目录:/data/software Mysql目录安装位置:/us ...
- Python模块的导入以及软件开发规范
Python文件的两种用途 1 . 当脚本直接使用,直接当脚本运行调用即可 def func(): print("from func1") func() 2 . 当做模块被导入使用 ...
- Visual Studio 2017离线安装失败:安装程序清单签名验证失败
解决办法: 方法1:运行gpeidit.msc,然后 Windows 设置-安全设置->本地策略-安全选项-系统机密->将FIPS兼容算法用于加密.哈希和签名-设置禁用 方法2:删除vs ...