spring4.2更好的应用事件
1.基于注解驱动事件监听器:现在可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener来匹配方法签名.
@Component
public class MyListener {
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) { }
}
此方法签名定义了你感兴趣的事件类型.也可以定义SpELg表达式来匹配处理这个事件.假设事件的定义如下:
public class OrderCreatedEvent implements CreationEvent<Order> {
private boolean awesome;
public boolean isAwesome() {
return this.awesome;
}
}
下面的例子事件监听器将同时满足以下情况才会被调用:a.它是CreationEvent<Order>类型的事件;b.此事件的awesome标志为true.
@Component
public class MyComponent {
@EventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) { } }
2.上面只提到了注册事件和事件定义,再来看看事件的发布.
对于任何一个使用@EventListener注解的方法,你可以定义一个非void返回类型.如果你返回一个非null值作为处理一个常规事件的结果,我们会将此结果作为一个新事件来发送.
你可能注意到OrderCreatedEvent并没有继承ApplicationEvent,我们觉得是时候让你灵活发布任意事件,而不强迫你去继承ApplicationEvent.ApplicationEventPublisher已被扩展来允许你发布任意对象.当这个对象不是一个ApplicationEvent,我们会使用PayloadApplicationEvent来为你包装.以下例子演示了你如何使用ApplicationEventPublisher来发送一个OrderCreatedEvent:
@Component
public class MyComponent {
private final ApplicationEventPublisher publisher;
@Autowired
public MyComponent(ApplicationEventPublisher publisher) {
this.publisher=publisher;
}
public void createOrder(Order order) {
this.publisher.publishEvent(new OrderCreatedEvent(order));
} }
3.事务边界事件
另一个受欢迎的改善是一个事件的监听器绑定到该事务一个阶段的能力。典型的例子是当事务成功完成时,再处理这个事件.下面以这样的方式重写上面的例子,当生产者运行的事务已成功完成时,此订单创建事件才会被处理.
@Component
public class MyComponent {
@TransactionalEventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) { } }
功能的实现大致:
a.注册Listener:实例化spring容器的时候会注册一个org.springframework.context.event.EventListenerMethodProcessor这样的Bean,完成初始化,会调用它的兵后置回调afterSingletonsInstantiated()方法:
@Override
public void afterSingletonsInstantiated() {
List<EventListenerFactory> factories = getEventListenerFactories();
String[] allBeanNames = this.applicationContext.getBeanNamesForType(Object.class);
for (String beanName : allBeanNames) {
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
Class<?> type = this.applicationContext.getType(beanName);
try {
processBean(factories, beanName, type);
}catch (RuntimeException e) {
throw new BeanInitializationException("Failed to process @EventListener " +
"annotation on bean with name '" + beanName + "'", e);
}
}
}
}
迭代每个Bean进行processBean(factories, beanName, type)处理.
protected void processBean(List<EventListenerFactory> factories, String beanName, final Class<?> type) {
Class<?> targetType = getTargetClass(beanName, type);
if (!this.nonAnnotatedClasses.contains(targetType)) {
final Set<Method> annotatedMethods = new LinkedHashSet<Method>(1);
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(targetType);
for (Method method : methods) {
//在这个方法上查找EventListener注解
EventListener eventListener = AnnotationUtils.findAnnotation(method, EventListener.class);
if (eventListener == null) {
continue;
}
for (EventListenerFactory factory : factories) {
if (factory.supportsMethod(method)) {
if (!type.equals(targetType)) {
method = getProxyMethod(type, method);
}
//使用这个方法创建一个ApplicationListener对象
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, type, method);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter)applicationListener)
.init(this.applicationContext, this.evaluator);
}
//添加到applicationContext的事件广播器
this.applicationContext.addApplicationListener(applicationListener);
annotatedMethods.add(method);
break;
}
}
}
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(type);
if (logger.isTraceEnabled()) {
logger.trace("No @EventListener annotations found on bean class: " + type);
}
}
else {
// Non-empty set of methods
if (logger.isDebugEnabled()) {
logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName +
"': " + annotatedMethods);
}
}
}
}
b.通过ApplicationEventPublisher发布事件:入口在org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object),再调用重载方法
protected void publishEvent(Object event, ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
final ApplicationEvent applicationEvent;
//这里可以看出如果event不是ApplicationEvent类型,就会使用PayloadApplicationEvent进行包装
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<Object>(this, event);
if (eventType == null) {
eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
}
}
//通过事件广播器进行广播事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
spring4.2更好的应用事件的更多相关文章
- javascript中的事件冒泡和事件捕获
1.事件冒泡 IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).以下面的HTML ...
- javaScirpt事件详解-原生事件基础(一)
事件 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间,通过监听特定事件的发生,你能响应相关的操作.图片引用:UI Events 事件流 ...
- DOM事件
在慕课网上学习了DOM事件探秘课程,特此整理了一下笔记. 慕课网DOM事件探秘课程地址:http://www.imooc.com/learn/138 事件 是文档或浏览器窗口中发生的特定的交互瞬间.[ ...
- jQuery 2.0.3 源码分析 事件体系结构
那么jQuery事件处理机制能帮我们处理那些问题? 毋容置疑首先要解决浏览器事件兼容问题 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数 提供了常用事件的便捷方法 支 ...
- 解密jQuery事件核心 - 模拟事件(四)
前几章已经把最核心的实现都分解过了,这一章我们看看jQuery是如何实现事件模拟的 在Internet Explorer 8和更低,一些事件change 和 submit本身不冒泡,但jQuery修改 ...
- 理解DOM事件流的三个阶段
本文主要解决两个问题: 1.什么是事件流 2.DOM事件流的三个阶段 事件流之事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张 ...
- 深入理解DOM事件机制系列第一篇——事件流
× 目录 [1]历史 [2]事件冒泡 [3]事件捕获[4]事件流 前面的话 javascript操作CSS称为脚本化CSS,而javascript与HTML的交互是通过事件实现的.事件就是文档或浏览器 ...
- 你真的了解DOM事件么?
你真的了解DOM事件么? 我们大家都知道,人与人之间的交流可以通过语言,文字,肢体动作,面部微表情等,但是你知道Javascript和HTML之间是通过什么进行交互的么?你又知道Javascript和 ...
- DOM事件揭秘-事件流
事件:文档/窗口中发生的特定的交互瞬间 瀑布流,图片轮播 动作都是通过事件触发的 课程内容: 1,理解事件流 2,使用时间处理程序 3,不同的事件类型 ie4.0以后, 事件流:描述的是从页面中接收事 ...
随机推荐
- 串口VMIN VTIME 详解
原文地址: 以前跟着做过VxWorks的开发,主要通信方式是串口,因为底层BSP包已经做好了,串口通信非常简单.后来接触Linux,在一块OK6410上跑Linux串口通信,才发现原来天真的以为甚是简 ...
- Codeforces Round #321 (Div. 2) Kefa and First Steps 模拟
原题连接:http://codeforces.com/contest/580/problem/A 题意: 给你一个序列,问你最长不降子串是多长? 题解: 直接模拟就好了 代码: #include< ...
- SQL-基础学习使用的数据库资料
-- ------------------------ Create Customers table-- ----------------------CREATE TABLE Customers( c ...
- Caused by: java.io.FileNotFoundException: rmi_keystore.jks (没有那个文件或目录)
解决方法:修改jmeter.properites: server.rmi.ssl.disable=true,关闭ssl功能 参考: https://blog.csdn.net/nielinqi520/ ...
- android wifi相关模块 命令列表 汇总
static final int BASE =Protocol.BASE_WIFI; 131072 static final intCMD_START_SUPPLICANT = BASE +11; ...
- PS 如何制作WIN7的玻璃化透明窗口效果
1 绘制一个圆角矩形,并将不透明度设为16%以及添加投影效果 2 再次添加外发光效果 3 新建一个图层,再填充一下这个圆角矩形(可以填充为任意颜色,只要和别的颜色区分开来) 4 选中这个区 ...
- react 自定义 TabBar 组件
1.创建 组件 src/components/TabBar/index.js /** * TabBar 组件 */ import React ,{ PureComponent } from 'reac ...
- 混合背包 hdu5410 CRB and His Birthday
传送门:点击打开链接 题意:你有M块钱,如今有N件商品 第i件商品要Wi块,假设你购买x个这种商品.你将得到Ai*x+Bi个糖果 问能得到的最多的糖果数 思路:很好的一道01背包和全然背包结合的题目 ...
- c#高级编程笔记----委托
因为定义委托基本上是定义一个新类,所以可以在定义类的任何相同地方定义委托,也就是说,可以在另一个类的内部定义,也可以在任何类的外部定义,还可以在名称空间中把委托定义为顶层对象.根据定义的可见性,和委托 ...
- C语言-回溯例2
组合问题 组合:从n个不同元素中取r个不重复的元素组成一个子集,而不考虑其元素的顺序,称为从n个中取r个的无重组合,例如OR = {1,2,3,4}, n = 4, r = 3则无重组合为: {1,2 ...