【sping揭秘】8、容器内部事件发布(一)
容器内部事件发布
Spring的applicationContext容器提供的容器内事件发布功能,是通过java提供的自定义事件实现的
事件类型:eventObject 类继承
事件监听:eventListener 接口实现
定义事件类型
package event; import java.util.EventObject; /**
*
* Title: MethodExecutionEvent.java
* Description: 定义一个自定义的事件对象
* @author xiaof
* @date 2018年3月28日
* @version 1.0
*
*/
public class MethodExecutionEvent extends EventObject {
/**
*
*/
private static final long serialVersionUID = -2324856893034735293L; private String methodName; /**
* 构造函数是,继承的类实现的
* @param source
*/
public MethodExecutionEvent(Object source) {
super(source);
} public MethodExecutionEvent(Object source, String methodName) {
super(source);
this.methodName = methodName;
} public String getMethodName() {
return methodName;
} public void setMethodName(String methodName) {
this.methodName = methodName;
} }
创建自定义事件类的监听接口
package event;
import java.util.EventListener;
public interface MethodExecutionEventListener extends EventListener {
/**
* 处理方法开始执行的时候发布的methodexecutionevent事件
* @param evt
*/
void onMethodBegin(MethodExecutionEvent evt);
/**
* 处理方法开结束执行的时候发布的methodexecutionevent事件
* @param evt
*/
void onMethodEnd(MethodExecutionEvent evt);
}
发布事件
package event; import java.util.ArrayList;
import java.util.List; /**
*
* Title: MethodExeuctionEventPublisher.java
* Description: 事件发布
* @author xiaof
* @date 2018年3月28日
* @version 1.0
*
*/
public class MethodExeuctionEventPublisher { private List<MethodExecutionEventListener> listeners = new ArrayList<MethodExecutionEventListener>(); public void methodToMonitor() {
MethodExecutionEvent event2Publish = new MethodExecutionEvent(this, "methodToMonitor");
this.publishEvent(MethodExecutionStatus.BEGIN, event2Publish);
//实际其他方法逻辑 this.publishEvent(MethodExecutionStatus.END, event2Publish); } protected void publishEvent(MethodExecutionStatus status, MethodExecutionEvent methodExecutionEvent) { List<MethodExecutionEventListener> copyListeners = new ArrayList<MethodExecutionEventListener>(listeners); //循环发布
for(MethodExecutionEventListener listener : copyListeners) { if(MethodExecutionStatus.BEGIN.equals(status)) {
listener.onMethodBegin(methodExecutionEvent);
} else {
listener.onMethodEnd(methodExecutionEvent);
}
}
} public void addMethodExecutionListener(MethodExecutionEventListener listener) {
this.listeners.add(listener);
} public void removeListener(MethodExecutionEventListener listener) {
if(this.listeners.contains(listener)) {
this.listeners.remove(listener);
}
} public void removeAllListeners() {
this.listeners.clear();
} public static void main(String[] args) { MethodExeuctionEventPublisher eventPublisher = new MethodExeuctionEventPublisher(); eventPublisher.addMethodExecutionListener(new SimpleMethodExecutionEventListener()); eventPublisher.methodToMonitor(); }
}
那么spring的容器内事件的发布类结构是什么样的呢?
Spring的事件类型分一下三种

我们主要使用一下几个

在spring容器中,这四个重上到下,分别是:
容器关闭的时候发布的事件类型
容器在初始化的时候或者刷新的时候发布
当使用 ConfigurableApplicationContext 接口中的 start() 方法启动 ApplicationContext 时,该事件被发布
当使用 ConfigurableApplicationContext 接口中的 stop() 方法停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作。
RequestHandledEvent web请求处理后发布的事件
spring监听事件
application在启动的时候,会自动识别并加载eventlistner类型bean定义。
一旦容器内有事件发布,将通知这些注册到容器的eventlistener
ApplicationListener
Spring发布事件
ApplicationEventPublisher 接口 实现对象 ApplicationContext 也是一个事件发布对象
这里做一个小测试:
package cn.cutter.start.event; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.stereotype.Component; @Component
public class MyStartEventHandler implements ApplicationListener<ContextStartedEvent> { @Override
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("cutter_point 启动application容器");
} }
package cn.cutter.start.event; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component; @Component
public class MyStopEventHandler implements ApplicationListener<ContextStoppedEvent> { @Override
public void onApplicationEvent(ContextStoppedEvent event) {
System.out.println("cutter_point 停止application容器");
} }
package cn.cutter.start.event; import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.stereotype.Component; @Component
public class MyStopEventHandler2 implements ApplicationListener<ContextStoppedEvent> { @Override
public void onApplicationEvent(ContextStoppedEvent event) {
// TODO Auto-generated method stub
System.out.println("cutter_point 停止application容器 222");
} }
package cn.cutter.start.resourceloader; import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader; public class FooBar implements ResourceLoaderAware { //资源加载器
private ResourceLoader resourceLoader; public void foo(String location) {
//这里有没有很熟悉
// ResourceDemo.class.getResource(location).getClass()
System.out.println(this.getResourceLoader().getResource(location).getClass());
} @Override
public void setResourceLoader(ResourceLoader resourceLoader) {
//这里进行resourceloader的注入
this.resourceLoader = resourceLoader;
} public ResourceLoader getResourceLoader() {
return resourceLoader;
} public void sayFoo() {
System.out.println("hi foo!");
} }
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="cn.cutter" /> <!-- 国际化配置 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basenames">
<list>
<value>i18/users</value>
<value>i18/errormsg</value>
</list>
</property> </bean> <bean id="ttmRateService" class="cn.cutter.simplefx.service.impl.MockTTMRateServiceImpl"></bean> <bean id="fooBar" class="cn.cutter.start.resourceloader.FooBar" /> <bean id="fooBar2" class="cn.cutter.start.resourceloader.FooBar2" /> <bean id="resourceDemo" class="cn.cutter.start.resourceloader.ResourceDemo">
<property name="resource">
<value>classpath:applicationContext-bean.xml</value>
</property>
</bean> <!-- <bean id="myObject" class="cn.cutter.start.bean.MyObject"></bean> --> <!-- <alias name="FXNewsProvider" alias="provideralias"/> --> <!-- <bean id="test4key2" ></bean> <bean id="" class="..." lazy-init="true">
<constructor-arg>
<ref bean="" parent=""/>
</constructor-arg> <property name="test1">
<value>ttttt1</value>
<idref bean="ttttt1"/>
</property> <property name="test2">
<list>
<value>test2value</value>
<ref bean="test2222"/>
<idref bean="test22222"/>
<bean class="..."></bean>
</list>
</property> <property name="test3">
<set>
<value>test2value</value>
<ref bean="test2222"/>
<idref bean="test22222"/>
<bean class="..."></bean>
</set>
</property> <property name="test4">
<map>
<entry key="test4key1">
<value>something</value>
</entry> <entry key-ref="test5key2">
<list>
<value>test2value</value>
<ref bean="test2222"/>
<idref bean="test22222"/>
<bean class="..."></bean>
</list>
</entry>
</map>
</property> </bean> --> </beans>
启动测试案例
@Test
public void testEvent() {
//这里出发start事件和stop事件,就是使用ConfigurableApplicationContext的start和stop事件
ConfigurableApplicationContext cac = (ConfigurableApplicationContext) before(); cac.start();
FooBar fooBar = (FooBar) cac.getBean("fooBar");
fooBar.sayFoo();
cac.stop(); }
运行截图

【sping揭秘】8、容器内部事件发布(一)的更多相关文章
- 【sping揭秘】9、容器内部事件发布(二)
写在前面---------------------------------- 命运多舛,痴迷淡然 不知下一步该往哪里走,现在应该是我的迷茫期... 加油,快点走出去!!! 聪明的网友们,你们有没有迷茫 ...
- 深入理解Spring的容器内事件发布监听机制
目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监 ...
- 【spring源码学习】spring的事件发布监听机制源码解析
[一]相关源代码类 (1)spring的事件发布监听机制的核心管理类:org.springframework.context.event.SimpleApplicationEventMulticast ...
- 从spring源码汲取营养:模仿spring事件发布机制,解耦业务代码
前言 最近在项目中做了一项优化,对业务代码进行解耦.我们部门做的是警用系统,通俗的说,可理解为110报警.一条警情,会先后经过接警员.处警调度员.一线警员,警情是需要记录每一步的日志,是要可追溯的,比 ...
- Spring事件发布与监听机制
我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 目录 ...
- Nacos源码分析-事件发布机制
温馨提示: 本文内容基于个人学习Nacos 2.0.1版本代码总结而来,因个人理解差异,不保证完全正确.如有理解错误之处欢迎各位拍砖指正,相互学习:转载请注明出处. Nacos的服务注册.服务变更等功 ...
- Spring 源码(8)Spring BeanPostProcessor的注册、国际化及事件发布机制
上一篇文章https://www.cnblogs.com/redwinter/p/16198942.html介绍了Spring的注解的解析过程以及Spring Boot自动装配的原理,大概回顾下:Sp ...
- Spring之事件发布系统
springboot应用,启动spring容器大致有如下几个过程: 容器开始启动 初始化环境变量 初始化上下文 加载上下文 完成 对应的Spring应用的启动器的监听器可以监听以上的过程,接口如下: ...
- spring 自定义事件发布及监听(简单实例)
前言: Spring的AppilcaitionContext能够发布事件和注册相对应的事件监听器,因此,它有一套完整的事件发布和监听机制. 流程分析: 在一个完整的事件体系中,除了事件和监听器以外,还 ...
随机推荐
- 移动赋值运算符(c++11)
1.概念 1)移动赋值运算符是一个重载的赋值运算符,参数为自身类的右值引用,返回值自身类的左值引用,由于不抛出任何异常,用noexcept指定(如果定义在类的外面,那么定义也要用noexcept指定) ...
- extern声明全局变量用法
在类之外声明一个成员变量,如: a.h CString name; class a{ }; a.cpp extern CString name; 然后就可以用name这个成员变量了. b.cpp ex ...
- 学习fortran77基础语法
Program ParamaterDefine Implicit None C FORTRAN变量名和关键字不区分大小写.但调用外部函数的话,需要在编译选项里指定 c 大小写等选项 因为链接器是区分大 ...
- @RequestBody jackson解析复杂的传入值的一个坑;jackson解析迭代数组;jackson多重数组;jakson数组
一.实际开发的一个问题. 传入一个json数组,数组中还嵌套数组,运用springboot+Jpa框架,@RequestBody注解传入数据 Controller @ApiOperation(valu ...
- BZOJ 1444 [Jsoi2009]有趣的游戏 (AC自动机 + 概率DP + Gauss)
1444: [Jsoi2009]有趣的游戏 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1382 Solved: 498[Submit][Statu ...
- Typecho 插件开发基础
<?php /** * 标题 插件说明 * * @package 添加标题 * @author Fan * @version 1.0.0 * @link http://cnblogs.com/f ...
- 微信 公众号平台 与 开放平台 获取用户信息 scope snsapi_login
微信公众号(公众平台) 和 微信开放平台 是两码事.公众号(公众平台)获取的scope只包括两种:snsapi_base 和snsapi_userinfo,前者是静默获取,用户无感知:后者是需要用户确 ...
- VGA的行场时序
之前碰到接收VGA时有的电脑可以有的电脑会出现画面偏移. 先来了解下数字显示器时序(DMT) DMT视频时序有四种: (1)Positive H & Positive V Syncs 行同步为 ...
- Windows网络编程(C/C++服务器编程)
Windows服务器网络编程 Linux服务器网络编程
- java注解学习(1)注解的作用和三个常用java内置注解
今天,记录一下自己学习的关于注解方面的知识. Annotation是从JDK5.0开始引入的新技术 Annotation的作用: -不是程序本身,可以对程序做出解释(这一点和注释没什么区别) -可以被 ...