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更好的应用事件的更多相关文章

  1. javascript中的事件冒泡和事件捕获

    1.事件冒泡 IE 的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).以下面的HTML ...

  2. javaScirpt事件详解-原生事件基础(一)

    事件 JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间,通过监听特定事件的发生,你能响应相关的操作.图片引用:UI Events 事件流 ...

  3. DOM事件

    在慕课网上学习了DOM事件探秘课程,特此整理了一下笔记. 慕课网DOM事件探秘课程地址:http://www.imooc.com/learn/138 事件 是文档或浏览器窗口中发生的特定的交互瞬间.[ ...

  4. jQuery 2.0.3 源码分析 事件体系结构

    那么jQuery事件处理机制能帮我们处理那些问题? 毋容置疑首先要解决浏览器事件兼容问题 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数 提供了常用事件的便捷方法 支 ...

  5. 解密jQuery事件核心 - 模拟事件(四)

    前几章已经把最核心的实现都分解过了,这一章我们看看jQuery是如何实现事件模拟的 在Internet Explorer 8和更低,一些事件change 和 submit本身不冒泡,但jQuery修改 ...

  6. 理解DOM事件流的三个阶段

    本文主要解决两个问题: 1.什么是事件流 2.DOM事件流的三个阶段 事件流之事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张 ...

  7. 深入理解DOM事件机制系列第一篇——事件流

    × 目录 [1]历史 [2]事件冒泡 [3]事件捕获[4]事件流 前面的话 javascript操作CSS称为脚本化CSS,而javascript与HTML的交互是通过事件实现的.事件就是文档或浏览器 ...

  8. 你真的了解DOM事件么?

    你真的了解DOM事件么? 我们大家都知道,人与人之间的交流可以通过语言,文字,肢体动作,面部微表情等,但是你知道Javascript和HTML之间是通过什么进行交互的么?你又知道Javascript和 ...

  9. DOM事件揭秘-事件流

    事件:文档/窗口中发生的特定的交互瞬间 瀑布流,图片轮播 动作都是通过事件触发的 课程内容: 1,理解事件流 2,使用时间处理程序 3,不同的事件类型 ie4.0以后, 事件流:描述的是从页面中接收事 ...

随机推荐

  1. hdu3572 任务分配/最大流判断满流

    题意:将n个任务分配为m个机器,给每个任务需要的天数(无需每天连续),和可以在哪些天去做该任务,求是否存在方案. 典型的任务(X)----天(Y)二分最大流,(因为这里任务是与天的关系)处理器控制流量 ...

  2. react native 添加mobx

    "babel-plugin-transform-decorators-legacy": "^1.3.5", "babel-preset-react-n ...

  3. FMDB使用的数据库的三种形式

    FMDB使用的数据库的三种形式   FMDB是iOS平台下一款优秀的第三方SQLite数据库框架.它以Objective-C的方式封装了SQLite的C语言API.使用起来,它更加面向对象,避免冗余的 ...

  4. Codeforces Gym 100338C Important Roads 最短路+Tarjan找桥

    原题链接:http://codeforces.com/gym/100338/attachments/download/2136/20062007-winter-petrozavodsk-camp-an ...

  5. [CQOI2018] 社交网络

    题目背景 当今社会,在社交网络上看朋友的消息已经成为许多人生活的一部分.通常,一个用户在社交网络上发布一条消息(例如微博.状态.Tweet等) 后,他的好友们也可以看见这条消息,并可能转发.转发的消息 ...

  6. LightOj 1215 Finding LCM

    Discription LCM is an abbreviation used for Least Common Multiple in Mathematics. We say LCM (a, b, ...

  7. 从源码解析 Spring JDBC 异常抽象

    初入学习 JDBC 操作数据库,想必大家都写过下面的代码: 数据库为:H2 如果需要处理特定 SQL 异常,比如 SQL 语句错误,这个时候我们应该怎么办? 查看 SQLException 源码,我们 ...

  8. 使用JAXP对xml文档进行DOM解析基础

    XML解析方式分为两种:dom和sax         dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式.       sax: ...

  9. DevExpress.XtraGrid 【转】

    http://www.cnblogs.com/zeroone/p/4574539.html DevExpress.XtraGrid控件使用 该控件类是一个表格控件,但是其具有很多方便而使用的功能,例如 ...

  10. sdut 面向对象程序设计上机练习九(对象指针)

    面向对象程序设计上机练习九(对象指针) Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 建立对象数组,内放5个学生数据(学号是字符串类型.成绩是整型).设 ...