一、概念

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内置事件的更多相关文章

  1. extjs组件添加事件监听的三种方式

    extjs对组件添加监听的三种方式  在定义组件的配置时设置 如代码中所示:  Java代码  xtype : 'textarea',  name : 'dataSetField',  labelSe ...

  2. 王立平--android事件监听的3种方式

    第一种通常在activity组件的oncreate事件中直接定义,直接动作. 这样的方式每一个控件都定义一次.通常不方便. Button btn = (Button) findViewById(R.i ...

  3. [转]extjs组件添加事件监听的三种方式

    原文地址:http://blog.csdn.net/y6300023290/article/details/18989635 1.在定义组件配置的时候设置 xtype : 'textarea', na ...

  4. Spring Boot实践——事件监听

    借鉴:https://blog.csdn.net/Harry_ZH_Wang/article/details/79691994 https://blog.csdn.net/ignorewho/arti ...

  5. SpringBoot的事件监听

    事件监听的流程分为三步:1.自定义事件,一般是继承ApplicationEvent抽象类.2.定义事件监听器,一般是实现ApplicationListener接口.3.a.启动的时候,需要将监听器加入 ...

  6. 关于事件监听机制的总结(Listener和Adapter)

    记得以前看过事件监听机制背后也是有一种设计模式的.(设计模式的名字记不清了,只记得背后实现的数据结构是数组.) 附上事件监听机制的分析图: 一个事件源可以承载多个事件(只要这个事件源支持这个事件就可以 ...

  7. js事件监听

    /* 事件监听器 addEventListener() removeEventListener() 传统事件绑定: 1.重复添加会,后添加的后覆盖前面的. */ 示例代码中的html结构: <b ...

  8. [JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播

    -->事件冒泡和捕获-->事件监听-->阻止事件传播 一.事件冒泡和捕获 1.概念:当给子元素和父元素定义了相同的事件,比如都定义了onclick事件,点击子元素时,父元素的oncl ...

  9. JS的事件监听机制

    很久以前有个叫Netscape的姑娘,她制订了Javascript的一套事件驱动机制(即事件捕获) 后来又有一个叫“IE”的小子,这孩子比较傲气,他认为“凭什么我要依照你的规则走”,于是他又创造了一套 ...

随机推荐

  1. 【vuejs面试题】务必熟知的vuejs面试题「务必收藏」

    如果能帮到你,点个赞吧,务必熟知的vuejs面试题「务必收藏」 vuejs 基础必备 1.active-class 是哪个组件的属性?嵌套路由怎么定义 (1).active-class 是 vue-r ...

  2. WPF拖拽文件(拖入拖出),监控拖拽到哪个位置,类似百度网盘拖拽

    1.往wpf中拖文件 // xaml <Grid x:Name="grid_11" DragOver="Grid_11_DragOver" Drop=&q ...

  3. pip和pip3的区别

    安装了python3之后,会有pip3 1. 使用pip install XXX 新安装的库会放在这个目录下面 python2.7/site-packages 2. 使用pip3 install XX ...

  4. Java中静态变量和实例变量的区别

    静态变量属于类的级别,而实例变量属于对象的级别. 主要区别有两点: 1,存放位置不同 类变量随着类的加载存在于方法区中,实例变量随着对象的对象的建立存在于堆内存中. 2,生命周期不同 类变量的生命周期 ...

  5. oracle PL/SQL编程基础知识

    在oracle中使用pl/sql来扩展SQL的功能,使得SQL能够更加的灵活,功能更加强大,效率更高.pl/sql让sql也能执行判断,循环等操作.主要记录一下pl/sql的基本语法和基本条件判断语句 ...

  6. 3Linux - 常用 Linux 命令的基本使用

    常用 Linux 命令的基本使用 转自 目标 理解学习 Linux 终端命令的原因 常用 Linux 命令体验 01. 学习 Linux 终端命令的原因 Linux 刚面世时并没有图形界面,所有的操作 ...

  7. 主流Linux发行版及联系

    一.主流Linux主流发行版 RedHat:Red Hat Linux是由Red Hat公司发行的一个Linux发行包.其1.0版本于1994年11月3日发行,虽然其历史不及Slackware般悠久, ...

  8. java 通过反射获取数组

    1.创建数组.设置数组元素.访问数组 一维数组: 多维数组: public Class<?> getComponentType() 返回表示数组组件类型的 Class.如果此类不表示数组类 ...

  9. MySQL新增用户及赋予权限

    创建用户 USE mysql; #创建用户需要操作 mysql 表 # 语法格式为 [@'host'] host 为 'localhost' 表示本地登录用户,host 为 IP地址或 IP 地址区间 ...

  10. 与Swing的相识

    参考自http://c.biancheng.net/swing/ Swing是一个用于Java GUI编程(图形界面设计)的工具包(类库):换句话说,java可以用来开发带界面的PC软件,使用到的工具 ...