Spring ApplicationListener 理解
在开发时有时候需要在整个应用开始运行时执行一些特定代码,比如初始化环境,准备测试数据、加载一些数据到内存等等。
在spring中可以通过ApplicationListener来实现相关的功能,加载完成后触发contextrefreshedevent事件(上下文件刷新事件)。
ApplicationContext事件机制是观察者设计模式的实现,通过ApplicationEvent类和ApplicationListener接口,可以实现ApplicationContext事件处理。
如果容器中有一个ApplicationListener Bean,每当ApplicationContext发布ApplicationEvent时,ApplicationListener Bean将自动被触发。这种事件机制都必须需要程序显示的触发。
其中spring有一些内置的事件,当完成某种操作时会发出某些事件动作。比如监听ContextRefreshedEvent事件,当所有的bean都初始化完成并被成功装载后会触发该事件,实现ApplicationListener<ContextRefreshedEvent>接口可以收到监听动作,然后可以写自己的逻辑。
同样事件可以自定义、监听也可以自定义,完全根据自己的业务逻辑来处理。
内置事件
序号 Spring 内置事件 & 描述
1 ContextRefreshedEvent
ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
2 ContextStartedEvent
当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序。
3 ContextStoppedEvent
当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
4 ContextClosedEvent
当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启。
5 RequestHandledEvent
这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件。
业务方监听事件举例
比如要监听ContextRefreshedEvent的时可以实现ApplicationListener接口,并且传入要监听的事件
@Component
public class TestApplicationListener implements ApplicationListener<ContextRefreshedEvent>{
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println(contextRefreshedEvent);
System.out.println("TestApplicationListener............................");
}
}
自定义事件
可以自定义事件,然后做完业务处理后手动发出。同上集成某个监听接口,接收到事件后进行业务处理
事件定义:
public class EmailEvent extends ApplicationEvent{
private String address;
private String text;
public EmailEvent(Object source, String address, String text){
super(source);
this.address = address;
this.text = text;
}
public EmailEvent(Object source) {
super(source);
}
//......address和text的setter、getter
}
监听定义
public class EmailNotifier implements ApplicationListener{
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof EmailEvent) {
EmailEvent emailEvent = (EmailEvent)event;
System.out.println("邮件地址:" + emailEvent.getAddress());
System.our.println("邮件内容:" + emailEvent.getText());
} else {
System.our.println("容器本身事件:" + event);
}
}
}
业务触发
public class SpringTest {
public static void main(String args[]){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//创建一个ApplicationEvent对象
EmailEvent event = new EmailEvent("hello","abc@163.com","This is a test");
//主动触发该事件
context.publishEvent(event);
}
}
不管是内置监听还是外部自定义监听一定要把实现ApplicationListener的类定义成一个bean才行,可以是通过注解@Component等也可以通过xml的方式去执行。
但是这个时候,会存在一个问题,在web 项目中(spring mvc),系统会存在两个容器,一个是root application context ,另一个就是我们自己的 projectName-servlet context(作为root application context的子容器)。
这种情况下,就会造成onApplicationEvent方法被执行两次。为了避免上面提到的问题,我们可以只在root application context初始化完成后调用逻辑代码,其他的容器的初始化完成,则不做任何处理,修改后代码。event.getApplicationContext().getDisplayName().equals("Root WebApplicationContext") 。
如下:(要把实现ApplicationListener的类定义成一个bean)
@Component
public class SpringStartedListener implements ApplicationListener<ContextRefreshedEvent> { private static final Logger logger = LoggerFactory.getLogger(SpringStartedListener.class);
private static final String CONTEXT_DISPLAY_NAME = "WebApplicationContext"; @Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Override
public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext().getDisplayName().indexOf(CONTEXT_DISPLAY_NAME) > -1) {
ConfigConstants.initConfig(); // 初始化配置
threadPoolTaskExecutor.submit(() -> {
//在这里启动netty
Server server = NettyServer.getInstance();
try {
logger.debug("NettyServer Starting...");
server.start();
} catch (InterruptedException e) {
logger.error("init NettyServer err:{}", e.getMessage(), e);
}
});
}
}
}
Spring ApplicationListener 理解的更多相关文章
- Java框架-Spring MVC理解001
Spring MVC理解 1.servlet--Spring MVC的本质 2.Spring MVC其实是一个工具,具体的理解可以分为两步:第一步,了解这个工具是怎么创建出来的:第二步,了解这个工具是 ...
- spring的理解
看过<fate系列>的博友知道,这是一个七位英灵的圣杯争夺战争.今天主要来谈谈圣杯的容器概念,以便对spring的理解. 圣杯: 圣杯本身是没有实体的,而是将具有魔术回路的存在(人)作为“ ...
- mybatis中两种取值方式?谈谈Spring框架理解?
1.mybatis中两种取值方式? 回答:Mybatis中取值方式有几种?各自区别是什么? Mybatis取值方式就是说在Mapper文件中获取service传过来的值的方法,总共有两种方式,通过 $ ...
- Spring深入理解(三)
Spring 中 AOP 特性详解 动态代理的实现原理 要了解 Spring 的 AOP 就必须先了解动态代理的原理,因为 AOP 就是基于动态代理实现的.动态代理还要从 JDK 本身说起. 在 Jd ...
- 怎么回答面试官:你对Spring的理解?
最近看了点Spring的源码,正好来稍微扯一扯,帮一部分培训班的朋友撕开一道口子,透透气.我自己都是看的培训班视频,所以也算培训班出身吧.所以下文开口闭口"培训班",不要觉得是我在 ...
- 谈一下spring 的理解
spring,大家基本都在使用,两个核心: 声明式事务AOP : 控制反转依赖注入IOC: 以前对控制反转和依赖注入很模糊,现在大概理解了意思,控制反转,有spring容易来控制bean 的创建,我们 ...
- Spring ApplicationListener使用方法及问题
使用场景 在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载.初始化缓存.特定任务的注册等等.这个时候我们就可以使用Spring提供的ApplicationListener来 ...
- spring IOC理解
用spring做了几个项目后发现,对spring的IOC理解还是不够清晰,今天就来总结下自己的理解(个人的一些见解) 以前用jsp+servlet做网站时,只是分了显示层(jsp),控制层(servl ...
- Spring ApplicationListener使用方法及二次调用问题解决
使用场景 在一些业务场景中,当容器初始化完成之后,需要处理一些操作,比如一些数据的加载.初始化缓存.特定任务的注册等等.这个时候我们就可以使用Spring提供的ApplicationListener来 ...
随机推荐
- HMM,MEMM,CRF模型的比较
本文参考自:http://blog.csdn.net/happyzhouxiaopei/article/details/7960876 这三个模型都可以用来做序列标注模型.但是其各自有自身的特点,HM ...
- 常用的系统架构 web服务器之iis,apache,tomcat三者之间的比较
常用的系统架构是: Linux + Apache + PHP + MySQL Linux + Apache + Java (WebSphere) + Oracle Windows Server 200 ...
- WooCommerce Shortcode 简码使用方式说明
WooCommerce 自帶的几个简易代码,可以用来插入文章和页面內容里面.下面简码安裝时会自动建立,因此,应该不需要使用在其他地方 : [woocommerce_cart] – 顯示購物車頁面 [w ...
- html5的常用函数
required 验证非空 readonly 文本只读 video 视频播放标签 Ogg 带有 Theora 视频编码和 Vorbis 音 ...
- Java基础知识陷阱(四)
本文发表于本人博客. 今天我们来说说关于java继承以及反射有关的问题,大家先看下下面代码,试问可以编译通过不,为什么具体说说原因? public class Test{ public static ...
- BZOJ 1316: 树上的询问
挺裸的点分治 刚开始想用map水过去,然后做p次点分治,然后T到自闭 最后发现可以sort一遍,然后去重,记录每个数出现的次数,这样就可以双指针,不会漏掉了 #include <bits/std ...
- GitHub上最热门的11款开源安全工具
恶意软件分析.渗透测试.计算机取证——GitHub托管着一系列引人注目的安全工具.足以应对各类规模下计算环境的实际需求. 作为开源开发领域的基石,“所有漏洞皆属浅表”已经成为一条着名的原则甚至是信条 ...
- quartz (二) Spring+Quartz实现定时任务的配置方法
JobDetail 设置执行的任务 :CronTrigger 触发器:设置执行的时间规则 ; Scheduler // 调度器,将任务与执行时间关联 本文转自:http://w ...
- maven 介绍(二)
本文内容主要摘自:http://www.konghao.org/index 内部视频 三.仓库 仓库:本地仓库:远程仓库:私有仓库(nexus) 1. nexus 的安装: 1). 下载并且解压缩 2 ...
- centos ssh免密码秘钥登录
假设从A主机ssh登录B主机,用秘钥代替密码,步骤如下: 1.在A主机上执行:ssh-keygen -t rsa 一切默认,不用输入密码,生成两个文件: /root/.ssh/id_rsa /roo ...