一、概念

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. Maven快速安装配置

    环境:windows7_x86  maven3.3.3   maven是管理项目的常用工具,不用安装,直接配置即可.在配置maven前,需要先安装JDK.   1,安装JDK(注意此版本的Maven要 ...

  2. django登录注册验证之密码包含特殊字符,确认密码一致实现,Form验证

    Form验证的原理 首先用户在注册界面提交表单,后台收到表单之后通过request.post取到数据然后传入已经写好的Form类 执行obj.is_valid()这里的obj为Form的实例,在For ...

  3. 3.css3中多个背景图片的用法

    (background-clip裁剪,background-position位置,background-origin定位,background-repeat是否重复) <!DOCTYPE htm ...

  4. 20140919-FPGA-有效观察设计中的差分信号

    今天回来坐在电脑前,打开Xilinx的Documentation Navigator寻找NCO相关的User Guide,但是在不经意中发现了一个这样的IP,我感觉对于观察设计中的查分信号十分有用.之 ...

  5. VMware Workstation key

    VMware workstation 11 Pro key VY790-6FF9M-H8D3Q-1PY5T-YFUTD AA5M8-8NGD3-M805Y-K5Q7G-X28E6 UY3TR-88W4 ...

  6. python 写matlab中的加性高斯白噪声AWGN

    定义 原始信号:x 噪声信号:n 信噪比:SNR 信号长度:N def wgn(x, snr): snr = 10**(snr/10.0) xpower = np.sum(x**2)/len(x) n ...

  7. dd命令注意:dd:unrecognized operand 'if'

    如果是 idd if=boot.bin 在等号两边不要有空格

  8. MyEclipse XML & XML架构教程:XML Schema (XSD)编辑器

    [MyEclipse CI 2019.4.0安装包下载] 1. MyEclipse中的XSD编辑 本文档介绍MyEclipse XML Schema(XSD)编辑器中的一些可用函数.XML Schem ...

  9. POJ-3436-ACM Computer Factory(最大流, 输出路径)

    链接: https://vjudge.net/problem/POJ-3436#author=0 题意: 为了追求ACM比赛的公平性,所有用作ACM比赛的电脑性能是一样的,而ACM董事会专门有一条生产 ...

  10. NOIP模拟赛(by hzwer) T3 小奇回地球

    [题目背景] 开学了,小奇在回地球的路上,遇到了一个棘手的问题. [问题描述] 简单来说,它要从标号为 1 的星球到标号为 n 的星球,某一些星球之间有航线. 由于超时空隧道的存在,从一个星球到另一个 ...