009-Spring Boot 事件监听、监听器配置与方式、spring、Spring boot内置事件
一、概念
1.事件监听的流程
步骤一、自定义事件,一般是继承ApplicationEvent抽象类
步骤二、定义事件监听器,一般是实现ApplicationListener接口
步骤三、启动时,需要将监听器加入到Spring容器中
步骤四、发布事件
对于配置监听器的方式【即第三步】
方式一、app.addListeners(new MyApplicationListener());添加监听器
方式二、把监听器使用纳入Spring配置中管理如使用@Component标注
方式三、再application.properties中添加context.listener.classes配置项配置
方式四、使用注解@EventListener在方法上,且该类需要在Spring上管理
2、示例【方式一】:
步骤一、自定义事件MyApplicationEvent
package com.lhx.spring.springboot_event; import org.springframework.context.ApplicationEvent; /**
* 定义事件
* @author Administrator
*
*/
public class MyApplicationEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L; public MyApplicationEvent(Object source) {
super(source);
}
}
步骤二、定义事件监听器MyApplicationListener
package com.lhx.spring.springboot_event;
import org.springframework.context.ApplicationListener;
public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
@Override
public void onApplicationEvent(MyApplicationEvent event) {
System.out.println("接收到事件:" + event.getClass());
}
}
步骤三、在App启动程序中添加以及发布
@SpringBootApplication
public class App {
public static void main(String[] args) {
// ConfigurableApplicationContext context = SpringApplication.run(App.class,
// args);
SpringApplication app = new SpringApplication(App.class);
app.addListeners(new MyApplicationListener());
ConfigurableApplicationContext context = app.run(args);
context.publishEvent(new MyApplicationEvent(new Object()));
context.close();
}
}
3、示例【方式二】:
注意:其实在示例步骤三,也可以用注解方式将时间监听器纳入Spring管理中
步骤一、与示例一一致
步骤二、将事件监听器添加@Component注解。
步骤三、启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(App.class);
//app.addListeners(new MyApplicationListener());
ConfigurableApplicationContext context = app.run(args);
context.publishEvent(new MyApplicationEvent(new Object()));
context.close();
}
}
4、示例【方式四】:
步骤一、与示例一一致
步骤二、与示例一一致
步骤三、增加单独处理类
package com.lhx.spring.springboot_event; import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; @Component
public class MyEventHandle {
@EventListener
public void event(MyApplicationEvent event) {
System.out.println("MyEventHandle 接收到事件:" + event.getClass());
} @EventListener
public void event2(ContextStoppedEvent event) {
System.out.println("应用停止 接收到事件:" + event.getClass());
}
}
步骤三、启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(App.class);、
ConfigurableApplicationContext context = app.run(args);
context.publishEvent(new MyApplicationEvent(new Object()));
context.close();
}
}
二、配置监听器的方式原理
1.方式三实现,在application.properties中添加context.listener.classes配置项配置
查看:DelegatingApplicationListener
public class DelegatingApplicationListener
implements ApplicationListener<ApplicationEvent>, Ordered { // NOTE: Similar to org.springframework.web.context.ContextLoader private static final String PROPERTY_NAME = "context.listener.classes";
核心逻辑
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
if (delegates.isEmpty()) {
return;
}
this.multicaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<ApplicationEvent> listener : delegates) {
this.multicaster.addApplicationListener(listener);
}
}
if (this.multicaster != null) {
this.multicaster.multicastEvent(event);
}
} @SuppressWarnings("unchecked")
private List<ApplicationListener<ApplicationEvent>> getListeners(
ConfigurableEnvironment environment) {
if (environment == null) {
return Collections.emptyList();
}
String classNames = environment.getProperty(PROPERTY_NAME);
List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>();
if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
try {
Class<?> clazz = ClassUtils.forName(className,
ClassUtils.getDefaultClassLoader());
Assert.isAssignable(ApplicationListener.class, clazz, "class ["
+ className + "] must implement ApplicationListener");
listeners.add((ApplicationListener<ApplicationEvent>) BeanUtils
.instantiateClass(clazz));
}
catch (Exception ex) {
throw new ApplicationContextException(
"Failed to load context listener class [" + className + "]",
ex);
}
}
}
AnnotationAwareOrderComparator.sort(listeners);
return listeners;
}
2、方式四实现
查看:EventListenerMethodProcessor的processBean
protected void processBean(final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType)) {
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
new MethodIntrospector.MetadataLookup<EventListener>() {
@Override
public EventListener inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
}
});
}
catch (Throwable ex) {
// An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
}
}
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
}
}
else {
// Non-empty set of methods
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(
method, this.applicationContext.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener)
.init(this.applicationContext, this.evaluator);
}
this.applicationContext.addApplicationListener(applicationListener);
break;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
beanName + "': " + annotatedMethods);
}
}
}
}
EventListener
annotatedMethods = MethodIntrospector.selectMethods(targetType,
new MethodIntrospector.MetadataLookup<EventListener>() {
@Override
public EventListener inspect(Method method) {
return AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
}
});
查看for
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
Method methodToUse = AopUtils.selectInvocableMethod(
method, this.applicationContext.getType(beanName));
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener)
.init(this.applicationContext, this.evaluator);
}
this.applicationContext.addApplicationListener(applicationListener);
break;
}
}
}
其中factory即EventListenerFactory factory
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.context.event; import java.lang.reflect.Method; import org.springframework.context.ApplicationListener; /**
* Strategy interface for creating {@link ApplicationListener} for methods
* annotated with {@link EventListener}.
*
* @author Stephane Nicoll
* @since 4.2
*/
public interface EventListenerFactory { /**
* Specify if this factory supports the specified {@link Method}.
* @param method an {@link EventListener} annotated method
* @return {@code true} if this factory supports the specified method
*/
boolean supportsMethod(Method method); /**
* Create an {@link ApplicationListener} for the specified method.
* @param beanName the name of the bean
* @param type the target type of the instance
* @param method the {@link EventListener} annotated method
* @return an application listener, suitable to invoke the specified method
*/
ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method); }
三、spring、Spring boot内置事件
1.Spring
jar包:Spring-context-4.3.13.RELEASE
包:org.springframwork.context.event;
常用:ContextClosedEvent、ContextStartedEvent、ContextStopedEvent
示例
@Component
public class MyEventHandle {
@EventListener
public void event2(ContextStoppedEvent event) {
System.out.println("应用停止 接收到事件:" + event.getClass());
}
}
当然:app中Context要停止
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(App.class);
ConfigurableApplicationContext context = app.run(args);
context.publishEvent(new MyApplicationEvent(new Object()));
context.stop();
}
}
2.Spring-boot
jar包:Spring-boot-1.5.9.RELEASE
包:org.springframework.boot.context.event;
常用:ApplicationEnvironmentPreparedEvent、ApplicationFailedEvent等
009-Spring Boot 事件监听、监听器配置与方式、spring、Spring boot内置事件的更多相关文章
- extjs组件添加事件监听的三种方式
extjs对组件添加监听的三种方式 在定义组件的配置时设置 如代码中所示: Java代码 xtype : 'textarea', name : 'dataSetField', labelSe ...
- 王立平--android事件监听的3种方式
第一种通常在activity组件的oncreate事件中直接定义,直接动作. 这样的方式每一个控件都定义一次.通常不方便. Button btn = (Button) findViewById(R.i ...
- [转]extjs组件添加事件监听的三种方式
原文地址:http://blog.csdn.net/y6300023290/article/details/18989635 1.在定义组件配置的时候设置 xtype : 'textarea', na ...
- Spring Boot实践——事件监听
借鉴:https://blog.csdn.net/Harry_ZH_Wang/article/details/79691994 https://blog.csdn.net/ignorewho/arti ...
- SpringBoot的事件监听
事件监听的流程分为三步:1.自定义事件,一般是继承ApplicationEvent抽象类.2.定义事件监听器,一般是实现ApplicationListener接口.3.a.启动的时候,需要将监听器加入 ...
- 关于事件监听机制的总结(Listener和Adapter)
记得以前看过事件监听机制背后也是有一种设计模式的.(设计模式的名字记不清了,只记得背后实现的数据结构是数组.) 附上事件监听机制的分析图: 一个事件源可以承载多个事件(只要这个事件源支持这个事件就可以 ...
- js事件监听
/* 事件监听器 addEventListener() removeEventListener() 传统事件绑定: 1.重复添加会,后添加的后覆盖前面的. */ 示例代码中的html结构: <b ...
- [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播
-->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...
- JS的事件监听机制
很久以前有个叫Netscape的姑娘,她制订了Javascript的一套事件驱动机制(即事件捕获) 后来又有一个叫“IE”的小子,这孩子比较傲气,他认为“凭什么我要依照你的规则走”,于是他又创造了一套 ...
随机推荐
- 【vuejs面试题】务必熟知的vuejs面试题「务必收藏」
如果能帮到你,点个赞吧,务必熟知的vuejs面试题「务必收藏」 vuejs 基础必备 1.active-class 是哪个组件的属性?嵌套路由怎么定义 (1).active-class 是 vue-r ...
- WPF拖拽文件(拖入拖出),监控拖拽到哪个位置,类似百度网盘拖拽
1.往wpf中拖文件 // xaml <Grid x:Name="grid_11" DragOver="Grid_11_DragOver" Drop=&q ...
- pip和pip3的区别
安装了python3之后,会有pip3 1. 使用pip install XXX 新安装的库会放在这个目录下面 python2.7/site-packages 2. 使用pip3 install XX ...
- Java中静态变量和实例变量的区别
静态变量属于类的级别,而实例变量属于对象的级别. 主要区别有两点: 1,存放位置不同 类变量随着类的加载存在于方法区中,实例变量随着对象的对象的建立存在于堆内存中. 2,生命周期不同 类变量的生命周期 ...
- oracle PL/SQL编程基础知识
在oracle中使用pl/sql来扩展SQL的功能,使得SQL能够更加的灵活,功能更加强大,效率更高.pl/sql让sql也能执行判断,循环等操作.主要记录一下pl/sql的基本语法和基本条件判断语句 ...
- 3Linux - 常用 Linux 命令的基本使用
常用 Linux 命令的基本使用 转自 目标 理解学习 Linux 终端命令的原因 常用 Linux 命令体验 01. 学习 Linux 终端命令的原因 Linux 刚面世时并没有图形界面,所有的操作 ...
- 主流Linux发行版及联系
一.主流Linux主流发行版 RedHat:Red Hat Linux是由Red Hat公司发行的一个Linux发行包.其1.0版本于1994年11月3日发行,虽然其历史不及Slackware般悠久, ...
- java 通过反射获取数组
1.创建数组.设置数组元素.访问数组 一维数组: 多维数组: public Class<?> getComponentType() 返回表示数组组件类型的 Class.如果此类不表示数组类 ...
- MySQL新增用户及赋予权限
创建用户 USE mysql; #创建用户需要操作 mysql 表 # 语法格式为 [@'host'] host 为 'localhost' 表示本地登录用户,host 为 IP地址或 IP 地址区间 ...
- 与Swing的相识
参考自http://c.biancheng.net/swing/ Swing是一个用于Java GUI编程(图形界面设计)的工具包(类库):换句话说,java可以用来开发带界面的PC软件,使用到的工具 ...