走在前面
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) {
...
}
}
从上面的示例中可以看到,如果可以发现此类信息,则方法参数通过其名称公开。条件表达式还公开了一个“根”变量,其中包含原始
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 构建。您还可以使用 start.spring.io 使用最新的 Spring Boot 快照构建创建示例项目,或者如果您非常懒惰,可以将此内容复制粘贴到您的 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>
与往常一样,我们欢迎社区反馈,请尝试这些功能,并让我们知道您是否遇到任何问题。