http://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2

Better application events in Spring Framework 4.2

 

FEBRUARY 11, 2015

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_COMMITAFTER_ROLLBACK and AFTER_COMPLETIONthat 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的更多相关文章

  1. [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 ...

  2. 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 ...

  3. 严重: 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 ...

  4. 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 ...

  5. spring定时器用Annotation兑现

    spring定时器用Annotation实现 0人收藏此文章, 我要收藏发表于3个月前 , 已有46次阅读 共0个评论 1.ApplicationContext.xml配置 a).需要在xmlns里面 ...

  6. 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 ...

  7. [置顶] struts2+hibernate+spring整合(annotation版)

    本博文使用struts2,hibernate,spring技术整合Web项目,同时分层封装代码,包含model层,DAO层,Service层,Action层. 在整合hibernate时使用annot ...

  8. 严重: 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 ...

  9. 严重: Exception sending context initialized event to listener instance of class

    问题描述:Exception sending context initialized event to listener instance of class org.springframework.w ...

随机推荐

  1. socket基本操作

    我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so ...

  2. 用slf4j+logback实现多功能日志解决方案 --- 转

    大家都知道,slf4j是原来log4j的作者写的一个新的日志组件,意思是简单日志门面接口,可以跟其他日志组件配合使用,常用的配合是slf4j+logback,无论从功能上还是从性能上都较之log4j有 ...

  3. HDU 1495 非常可乐 BFS搜索

    题意:有个为三个杯子(杯子没有刻度),体积为s,n,m,s=m+n, 刚开始只有体积为s的杯子装满可乐,可以互相倒,问你最少的次数使可乐均分,如果没有结果,输出-1; 分析:直接互相倒就完了,BFS模 ...

  4. JS注入操作页面对象

    在用selenium webdriver 编写web页面的自动化测试代码时,有时对页面对象的操作需要通过js语句去执行,selenium本身就支持执行js,我们在代码中import org.openq ...

  5. i++ 和 ++i 效率的分析

    我们通常在写for循环 的时候,要实现变量 i 的自增 1 :往往会在i++ 和++i中随便挑一种写,对于i++和++i的理解,我们往往停留在返回的值的不同,其实i++与++i在实现效率上也有一定的不 ...

  6. 微软Azure云主机及blob存储的网络性能测试

    http://www.cnblogs.com/sennly/p/4137024.html 微软Azure云主机及blob存储的网络性能测试 1. 测试目的 本次测试的目的在于对微软Azure的云主机. ...

  7. 50道经典的JAVA编程题 (16-20)

    50道经典的JAVA编程题 (16-20),用了快一个下午来做这10道题了,整理博客的时间貌似大于编程的时间啊..哈哈 [程序16]Nine.java 题目:输出9*9口诀. 1.程序分析:分行与列考 ...

  8. algorithm@ 大素数判定和大整数质因数分解

    #include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> #in ...

  9. Ubuntu 14.04.3 LTS 配置 DNS Server

    我们目的是用一台局域网机器完成 192.168.1.113 <-->cloudshield.com的解析,指定A记录和CNAME; 0.关于Ubuntu 14.04.2 LTS 下载.安装 ...

  10. python 继承和多态

    在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.Supe ...