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. CDOJ_24 八球胜负

    8球是一种台球竞赛的规则.台面上有7个红球.7个黄球以及一个黑球,当然还有一个白球.对于本题,我们使用如下的简化规则:红.黄两名选手轮 流用白球击打各自颜色的球,如果将该颜色的7个球全部打进,则这名选 ...

  2. Java中PO、BO、VO、DTO、POJO、DAO概念及其作用和项目实例图(转)

    PO(bean.entity等命名): Persistant Object持久对象,数据库表中的记录在java对象中的显示状态 最形象的理解就是一个PO就是数据库中的一条记录. 好处是可以把一条记录作 ...

  3. Android 自定义ListView Item侧滑删除

    本程序是基于网上开源项目修改而来,具体来源忘了,懒得搜了,如果有不合适的地方,请原作者联系我,我会及时回复和处理的! 该例子程序中主要包含两个ListView,一个是实现侧滑删除,一个是侧滑出菜单,代 ...

  4. 临远的activiti教程

    1. 简介 协议 下载 源码 必要的软件 JDK 6+ Eclipse Indigo 和 Juno 报告问题 试验性功能 内部实现类 2. 开始学习 一分钟入门 安装Activiti 安装Activi ...

  5. 学习笔记 Java类的封装、继承和多态 2014.7.10

    1.问题:toString()没搞懂? int a = 1; Integer aa = new Integer(a); //这是实现的过程 System.out.println("Hello ...

  6. log4net日志组件经验分享

    引自log4net日志组件经验分享 我们在开发WEB项目的时候,经常会出现这样的情况:在本地调试都是正常的,但是部署到服务器上就不行了.一般出现这种情况很大一部分原因是因为服务的环境和本地不同,数据库 ...

  7. 微信公众平台SDK for node

    实现了下面特性: 1.开启开发人员模式 2.解析微信请求參数 3.验证消息来源 4.被动回复文字消息 5.被动回复图文消息 6.获取access_token 7.创建自己定义菜单 地址:wechat ...

  8. 谈一次Linux的木马攻击数据爆满造成的Mysql无法启动

    起初以为是mysql它们之间的扩展没有开启! 后来发现,木马的确使它初始化了,最开始没有用图形化界面 而后,修改并且开启所有pdo扩展 VIM基本操作(除了插入,其它的命令前提是按ESC): 插入: ...

  9. java性能监控工具jcmd-windows

    jcmd Sends diagnostic command requests to a running Java Virtual Machine (JVM). Synopsis jcmd [-l|-h ...

  10. WMS8_条码界面操作简要说明(包装作业)

    说明:条码界面的主要用途是包装作业 这个客户端,完全是JS实现的     可以从 All operation看板视图 Picking的表单视图                 All operatio ...