领先一步
VMware 提供培训和认证,助您加速前进。
了解更多应用事件自 Spring 框架诞生之初就已存在,作为松耦合组件交换信息的一种手段。应用事件最知名的用法之一如下所示
@Component
public class MyListener
implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
...
}
}
这使得 MyListener
可以在上下文刷新时收到通知,从而可以在应用上下文完全启动时运行任意代码。
在 Spring Framework 4.2 中,我们改进了事件基础设施,主要涉及三个方面,我将在本文中进行解释。
现在,可以在事件类型中使用嵌套泛型信息来定义您的 ApplicationListener
实现,例如
public class MyListener
implements ApplicationListener<MyEvent<Order>> { ... }
分发事件时,会使用监听器的签名来确定其是否与传入事件匹配。
由于类型擦除,您需要发布一个解析您希望过滤的泛型参数的事件,例如
MyOrderEvent extends MyEvent<Order>
。可能存在其他变通方法,如果社区认为值得,我们乐意重新审视签名匹配算法。
最大的新特性是支持注解驱动的事件监听器,类似于我们在 Spring Framework 4.1 中关于 JMS 和 AMQP 端点的最新工作。简而言之,现在只需使用 @EventListener
注解托管 bean 的方法,即可自动注册与该方法签名匹配的 ApplicationListener
。上面的示例可以重写如下
@Component
public class MyListener {
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
@EventListener
是一个核心注解,其处理方式与 @Autowired
等注解类似,是透明的:使用 Java 配置时无需额外配置,现有的 <context:annotation-driven/>
元素可完全启用对其支持。
方法签名定义了您感兴趣的事件类型。还可以定义一个 SpEL 表达式,只有匹配该表达式才会处理事件。例如,考虑以下事件
public class OrderCreatedEvent implements CreationEvent<Order> { ... }
private boolean awesome;
public boolean isAwesome() { return this.awesome; }
....
}
以下示例展示了一个事件监听器,它仅针对 Order
的一个很棒的 CreationEvent
被调用(即如果 awesome
标志为 true
)
@Component
public class MyComponent {
@EventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
从上面的示例可以看出,如果可以发现方法参数信息,则通过其名称暴露方法参数。条件表达式还通过一个“root”变量暴露了原始的
ApplicationEvent
(#root.event
) 和实际的方法参数 (#root.args
)。
您可以为任何使用 @EventListener
注解的方法定义一个非 void
的返回类型。如果您在处理特定事件后返回一个非 null
值,我们会将该结果作为新事件发送。
您可能注意到我们的 OrderCreatedEvent
没有继承 ApplicationEvent
;我们认为现在是时候让您灵活地发布任意事件,而不是强制您继承 ApplicationEvent
。ApplicationEventPublisher
接口已扩展,允许您发布任何对象;当该对象不是 ApplicationEvent
时,我们会将其包装在一个 PayloadApplicationEvent
中。如果您想使用常规的 ApplicationListener
实现来监听此类任意事件,请记住这一点。
以下示例展示了如何使用 ApplicationEventPublisher
发送 OrderCreatedEvent
@Component
public class MyComponent {
private final ApplicationEventPublisher publisher;
@Autowired
public MyComponent(ApplicationEventPublisher publisher) { ... }
public void createOrder(Order order) {
// ....
this.publisher.publishEvent(new OrderCreatedEvent(order));
}
}
另一项受欢迎的改进是将事件监听器绑定到事务的某个阶段的能力。典型的例子是在事务成功完成时处理事件:这使得事件在当前事务的结果对监听器确实重要时,可以更灵活地使用。
Spring Framework 目前的结构使得上下文不感知事务支持,我们显然不想偏离这一非常合理的原则,因此我们构建了一个开放基础设施,允许注册额外组件并影响事件监听器的创建方式。
事务模块实现了一个 EventListenerFactory
,它查找新的 @TransactionalEventListener
注解。当存在此注解时,将注册一个感知事务的扩展事件监听器,而不是默认的监听器。
让我们重用上面的示例,并将其改写,使得只有当生产者运行的事务成功完成时,才会处理订单创建事件
@Component
public class MyComponent {
@TransactionalEventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
没什么可多说的,对吧? @TransactionalEventListener
是一个常规的 @EventListener
,并且还暴露了一个 TransactionPhase
,默认值为 AFTER_COMMIT
。您还可以关联事务的其他阶段(BEFORE_COMMIT
、AFTER_ROLLBACK
和 AFTER_COMPLETION
,后者是 AFTER_COMMIT
和 AFTER_ROLLBACK
的别名)。
默认情况下,如果没有事务正在运行,事件根本不会发送,因为我们显然无法遵守请求的阶段,但在 @TransactionalEventListener
中有一个 fallbackExecution
属性,它告诉 Spring 如果没有事务,则立即调用监听器。
如果您想在 4.2 的第一个里程碑版本发布前试用此功能,请通过我们的snapshot 仓库获取每夜构建的 SNAPSHOT 版本。您也可以使用最新的 Spring Boot snapshot 版本,通过start.spring.io创建一个示例项目,或者如果您非常懒,可以直接将以下内容复制粘贴到您的 shell 中
$ curl https://start.spring.io/starter.tgz -d artifactId=events-demo \
-d baseDir=events-demo -d bootVersion=1.2.2.BUILD-SNAPSHOT | tar -xzvf -
并将项目更新为使用 Spring Framework 4.2.0.BUILD-SNAPSHOT
<properties>
...
<spring.version>4.2.0.BUILD-SNAPSHOT</spring.version>
</properties>
一如既往,我们欢迎社区反馈,请试用这些功能,如果您遇到任何问题,请告知我们。