Spring 4.2 annotation event Publisher/Listener
http://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
Better application events in Spring Framework 4.2
Application events are available since the very beginning of the Spring framework as a mean for loosely coupled components to exchange information. One of the most well known usage of application events is the following:
@Component
public class MyListener
implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
...
}
}
This allows MyListener
to be notified when the context has refreshed and one can use that to run arbitrary code when the application context has fully started.
In Spring Framework 4.2 we have revisited the event infrastructure in three main areas that I am going to explain in this post.
Generics support
It is now possible to define your ApplicationListener
implementation with nested generics information in the event type, something like:
public class MyListener
implements ApplicationListener<MyEvent<Order>> { ... }
When dispatching an event, the signature of your listener is used to determine if it matches said incoming event.
Due to type erasure you need to publish an event that resolves the generics parameter you would filter on, something like
MyOrderEvent extends MyEvent<Order>
. There might be other workarounds and we are happy to revisit the signature matching algorithm if the community thinks it worthwhile.
Annotation-driven event listener
The biggest new feature is the support of annotation-driven event listeners, similar to our recent work on JMS and AMQP endpoints in Spring Framework 4.1. In a nutshell, it is now possible to simply annotate a method of a managed-bean with @EventListener
to automatically register an ApplicationListener
matching the signature of the method. Our example above can be rewritten as follows:
@Component
public class MyListener {
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
@EventListener
is a core annotation that is handled transparently in a similar fashion as@Autowired
and others: no extra configuration is necessary with java config and the existing<context:annotation-driven/>
element enables full support for it.
The method signature defines the event type that you’re interested in. It is also possible to define a SpEL expression that should match in order to handle the event. For instance, consider the following event:
public class OrderCreatedEvent implements CreationEvent<Order> { ... }
private boolean awesome;
public boolean isAwesome() { return this.awesome; }
....
}
The following example showcases an event listener that will only be invoked for an awesomeCreationEvent
of Order
(i.e. if the awesome
flag is true
):
@Component
public class MyComponent {
@EventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
As you can see from the sample above, method arguments are exposed via their names if such information can be discovered. The condition expression also exposes a “root” variable with the raw
ApplicationEvent
(#root.event
) and the actual method arguments (#root.args
).
Publishing events
You can define a non-void
return type for any method annotated with @EventListener
. If you return a non null
value as the result of the processing of a particular event, we’ll send that result as a new event for you.
You may have noticed that our OrderCreatedEvent
does not extend fromApplicationEvent
; we felt it was about time to give you the flexibility to publish any arbitrary event and not force you to extend from ApplicationEvent
. TheApplicationEventPublisher
interface has been extended to allow you to publish any object; when said object isn’t an ApplicationEvent
, we wrap it in a PayloadApplicationEvent
for you. Remember this if you want to listen to such arbitrary event using a regularApplicationListener
implementation.
The following sample shows how you can use ApplicationEventPublisher
to send anOrderCreatedEvent
:
@Component
public class MyComponent {
private final ApplicationEventPublisher publisher;
@Autowired
public MyComponent(ApplicationEventPublisher publisher) { ... }
public void createOrder(Order order) {
// ....
this.publisher.publishEvent(new OrderCreatedEvent(order));
}
}
Transaction bound events
Another popular improvement is the ability to bind the listener of an event to a phase of the transaction. The typical example is to handle the event when the transaction has completed successfully: this allows events to be used with more flexibility when the outcome of the current transaction actually matters to the listener.
Spring Framework is currently structured in such a way that the context is not aware of the transaction support and we obviously didn’t want to deviate from that very sane principle so we built an open infrastructure to allow additional components to be registered and influence the way event listeners are created.
The transaction module implements an EventListenerFactory
that looks for the new@TransactionalEventListener
annotation. When this one is present, an extended event listener that is aware of the transaction is registered instead of the default.
Let’s reuse our example above and rewrite it in such a way that the order creation event will only be processed when the transaction in which the producer is running has completed successfully:
@Component
public class MyComponent {
@TransactionalEventListener(condition = "#creationEvent.awesome")
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
...
}
}
Not much to see, right? @TransactionalEventListener
is a regular @EventListener
and also exposes a TransactionPhase
, the default being AFTER_COMMIT
. You can also hook other phases of the transaction (BEFORE_COMMIT
, AFTER_ROLLBACK
and AFTER_COMPLETION
that is just an alias for AFTER_COMMIT
and AFTER_ROLLBACK
).
By default, if no transaction is running the event isn’t sent at all as we can’t obviously honor the requested phase, but there is a fallbackExecution
attribute in@TransactionalEventListener
that tells Spring to invoke the listener immediately if there is no transaction.
Try it out!
If you want to give this a try before the first milestone release of 4.2, grab a nightly SNAPSHOT build via our snapshot repository. You can also create a sample project usingstart.spring.io using the latest Spring Boot snapshot build, or if you’re super lazy you can copy/paste this in your 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 -
And update the project to use Spring Framework 4.2.0.BUILD-SNAPSHOT
<properties>
...
<spring.version>4.2.0.BUILD-SNAPSHOT</spring.version>
</properties>
As always, we welcome community feedback, please try these features and let us know if you run into any issue.
Spring 4.2 annotation event Publisher/Listener的更多相关文章
- [key]严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener(Spring配置异常)
详细错误为: 严重: Exception sending context initialized event to listener instance of class org.springframe ...
- Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- 严重: Exception sending context initialized event to listener instance of class org.springframework.we
2014-6-1 0:47:25 org.apache.catalina.core.AprLifecycleListener init 信息: The APR based Apache Tomcat ...
- Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener org.springframework.beans.factory.BeanCreationException:
严重: Exception sending context initialized event to listener instance of class org.springframework.we ...
- spring定时器用Annotation兑现
spring定时器用Annotation实现 0人收藏此文章, 我要收藏发表于3个月前 , 已有46次阅读 共0个评论 1.ApplicationContext.xml配置 a).需要在xmlns里面 ...
- Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener. ...nested exception is java.lang.NoSuchMethodError:
ssh 中,项目部署到服务器的时候,出现这样的奇葩的事情: 21-Oct-2017 11:27:15.953 INFO [localhost-startStop-1] org.apache.catal ...
- [置顶] struts2+hibernate+spring整合(annotation版)
本博文使用struts2,hibernate,spring技术整合Web项目,同时分层封装代码,包含model层,DAO层,Service层,Action层. 在整合hibernate时使用annot ...
- 严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
十月 30, 2019 11:12:35 下午 org.apache.catalina.core.StandardContext listenerStart 严重: Exception sending ...
- 严重: Exception sending context initialized event to listener instance of class
问题描述:Exception sending context initialized event to listener instance of class org.springframework.w ...
随机推荐
- JVM内存结构之一--总体介绍
Java 虚拟机在执行Java程序的时候会把它管理的内存区域划为几部分,这一节我们就来解析一下Java的内存区域. 有的人把JVM管理的内存简单地分为堆内存和栈内存,这样分未免有些太肤浅了. Java ...
- java类加载器学习2——自定义类加载器和父类委托机制带来的问题
一.自定义类加载器的一般步骤 Java的类加载器自从JDK1.2开始便引入了一条机制叫做父类委托机制.一个类需要被加载的时候,JVM先会调用他的父类加载器进行加载,父类调用父类的父类,一直到顶级类加载 ...
- andorid 进度条
SeekBar类似于ProgressBar,但是ProgressBar的主要功能是让用户知道目前的状态,而SeekBar的功能在于让用户调整进度,举个例子,在音乐播放器中,可以通过调整SeekBar来 ...
- 【暑假】[实用数据结构]UVAlive 3942 Remember the Word
UVAlive 3942 Remember the Word 题目: Remember the Word Time Limit: 3000MS Memory Limit: Unknown ...
- NOIP2004 合唱队列
三.合唱队形 (chorus.pas/dpr/c/cpp) [问题描述] N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形. 合唱队形是指这样的一种队形:设K位 ...
- php 仿百度文库
http://www.haosblog.com/?mod=article_read&id=386
- VMware 克隆虚拟机或加载新的已安装虚拟机时System eth0不能使用的解决方法
近年来的大数据应用特别热,特别是Hadoop和Spark.但大家使用这些分布式文件系统和计算框架都需要一个分布式的集群环境,而大家手头一般没有多余的机器部署master和多个slave节点,就只能在V ...
- poj1848 Tree
.....是我多想了. 我想开f[][0~3],看到百度上的题解都是[0~2]的,我就改了 方程不是特别难想.. f代表最小代价 f[i][0]是子树有环过i f[i][1]是子树除了i都成环了 f[ ...
- 单节点伪分布集群(weekend110)的HBase子项目启动顺序
伪分布模式下,如(weekend110)hbase-env.sh配置文档中的HBASE_MANAGES_ZK的默认值是true,它表示HBase使用自身自带的Zookeeper实例.但是,该实例只能为 ...
- soliworks三维机柜布局(二)创建设备位置
首先声明对三维机柜布局来说,此步骤不是必须的.(创建solidworks装配体文件时,若是创建了位置就可以选择是否为每个位置创建一个装配体,没有创建位置的话只能选择创建整个工程的装配体文件) 在菜单栏 ...