文档章节

spring中的event listener模式和解耦

烀饼
 烀饼
发布于 2012/02/10 10:41
字数 493
阅读 9202
收藏 14

event,listener是observer模式一种体现,在spring 3.0.5中,已经可以使用annotation实现event和eventListner里。
我们以spring-webflow里的hotel booking为例,看一下实现,步骤如下:
1,建立event

public class BookingCreatedEvent extends ApplicationEvent {
 private static final long serialVersionUID = 3039313222160544111L;

 private Booking booking;

 public BookingCreatedEvent(Object source) {
  super(source);
 }

 public BookingCreatedEvent(Object source, Booking booking) {
  super(source);
  this.booking = booking;
 }

 public Booking getBooking() {
  return booking;
 }
}

event需要继承ApplicationEvent。

2,建立listener

@Component
public class BookingEventsListener implements ApplicationListener<BookingCreatedEvent> {
 private static final Logger log = Logger.getLogger();

 //listener实现
 public void onApplicationEvent(BookingCreatedEvent event) {
  log.debug("bookingId:" + event.getBooking().getId());
  //do something
 }
}

listener需要实现ApplicationListener。
注意在spring 3.0.5中的ApplicationListener是带泛型的,这样BookingEventsListener只会监听BookingCreatedEvent事件。
另外可以用@Component来注册组件,这样就不需要在spring的配置文件中指定了。

3,触发event

@Service("bookingService")
@Repository
public class JpaBookingService implements BookingService, ApplicationContextAware {

 private ApplicationContext context;

 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  log.debug("Autowired applicationContext");
  this.context = applicationContext;
 }

 //省略的代码
 
 @Transactional
 public void persistBooking(Booking booking) throws HibernateException, SQLException {
  em.persist(booking);
  log.debug("fire BookingCreatedEvent");
  BookingCreatedEvent bookingCreatedEvent = new BookingCreatedEvent(this, booking);
  //触发event
  this.context.publishEvent(bookingCreatedEvent);
 }
}

触发要实现ApplicationContextAware,用于引入ApplicationContext,由于bookingService也是spring组件,所以在系统启动的时候,ApplicationContext已经注入。也可以用如下方式直接注入ApplicationContext。

@Autowired
private ApplicationContext applicationContext;

那么event listener这种模式的好处是什么呢?举个例子,如果客人booking了hotel以后,系统要发email给客人,那我们就可以在listener的do something处加入发送email的代码。
上面我们讲起用@Component把listener注册成了spring的组件,这样listener的用途是在runtime的时候解耦。
而如果我们把listener用配置文件的方式注册的话,主要的用途是在部署时解耦。
在实际应用中,两种情况都有。

另外要注意的一点是,service和listener是同步的,在service中的persistBooking有注册@Transactional的情况下,listener中的do something和service中的persistBooking是在同一个tansaction下。
如果要做异步,需要通过MQ或者数据库中转。

 

© 著作权归作者所有

共有 人打赏支持
烀饼
粉丝 5
博文 4
码字总数 2598
作品 0
宝山
部门经理
私信 提问
加载中

评论(4)

zoharfang
zoharfang
请问如何实现所有的listener与event在同一个事务之内,如果有一个listener操作失败,所有的listerner和event都回滚,你说他们本来是同一个事务的我试了不行啊
chienjerry
chienjerry
谢谢分享,很有用!
烀饼
烀饼

引用来自“ZhouZhefu”的评论

谢谢分享。要实现event异步处理,若处理模块在同一JVM内,用MQ就小题大做了,使用Spring提供的TaskExecutor比较合适。

不知朋友可曾涉及拦截Transaction的相关event,比如,需要异步处理一个事件,但又必须保证该异步处理代码只在transaction成功提交之后才能执行。初步想法是,覆盖ApplicationEventMulticaster的multicaster() 方法,令其对transaction相关的event进行特殊处理。不过目前尚未找到有效的过滤该类event和listener的方法,此文章似乎给出了一个方案,但具体并不可行,因为目前Spring框架不存在TransactionAware这个接口。
http://stackoverflow.com/questions/3492380/spring-transaction-annotations-execute-on-success

如果你listener是有事务的,本来就可以保证只有整个事务成功提交以后,listener才会被提交。因为其实他们是同一个事务。
ZhouZhefu
ZhouZhefu
Sorry,是multicastEvent() 方法,不是multicaster()
ZhouZhefu
ZhouZhefu
谢谢分享。要实现event异步处理,若处理模块在同一JVM内,用MQ就小题大做了,使用Spring提供的TaskExecutor比较合适。

不知朋友可曾涉及拦截Transaction的相关event,比如,需要异步处理一个事件,但又必须保证该异步处理代码只在transaction成功提交之后才能执行。初步想法是,覆盖ApplicationEventMulticaster的multicaster() 方法,令其对transaction相关的event进行特殊处理。不过目前尚未找到有效的过滤该类event和listener的方法,此文章似乎给出了一个方案,但具体并不可行,因为目前Spring框架不存在TransactionAware这个接口。
http://stackoverflow.com/questions/3492380/spring-transaction-annotations-execute-on-success
Spring源码-监听事件Applica**Listener和Applica**Event源码分析

Spring源码-监听事件ApplicationListener和ApplicationEvent源码分析 Spring中ApplicationListener和ApplicationEvent是典型的事件驱动模型,也就是我们常说的发布-订阅模型 。其实我们在开发...

秋日芒草
05/12
0
0
SpringBoot | 第三十二章:事件的发布和监听

前言 今天去官网查看资料时,在特性中看见了章节。想想,的事件应该是在版本就发布的功能了,并越来越完善,其为和之间的消息通信提供了支持。比如,我们可以在用户注册成功后,发送一份注册...

oKong
11/06
0
0
第五章 第一节 spring-context之ApplicationContextEvent

前言 ApplicationListener是对application生命周期的监听体制。 类依赖图 ApplicationListener体系 ApplicationEvent体系 ApplicationEventMulticaster ApplicationEventMulticaster只有一个......

鸟菜啊
08/04
0
0
Spring5源码解析-Spring框架中的事件和监听器

事件和平时所用的回调思想在与GUI(JavaScript,Swing)相关的技术中非常流行。而在Web应用程序的服务器端,我们很少去直接使用。但这并不意味着我们无法在服务端去实现一个面向事件的体系结构...

Java小铺
08/10
0
0
OPEN SESSION IN VIEW配置

使用Hibernate/Spring/Struts架构,配置使用Spring的OpenSessionInView Filter,但是发现不生效,lazy的集合属性在页面访问的时候仍然报session已经关闭的错误。我和他一起检查了所有的配置和...

红番茄
2012/05/07
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring应用学习——AOP

1. AOP 1. AOP:即面向切面编程,采用横向抽取机制,取代了传统的继承体系的重复代码问题,如下图所示,性能监控、日志记录等代码围绕业务逻辑代码,而这部分代码是一个高度重复的代码,也就...

江左煤郎
40分钟前
1
0
eclipse的版本

Eclipse各版本代号一览表 Eclipse的设计思想是:一切皆插件。Eclipse核心很小,其它所有功能都以插件的形式附加于Eclipse核心之上。 Eclipse基本内核包括:图形API(SWT/Jface),Java开发环...

mdoo
42分钟前
1
0
SpringBoot源码:启动过程分析(一)

本文主要分析 SpringBoot 的启动过程。 SpringBoot的版本为:2.1.0 release,最新版本。 一.时序图 还是老套路,先把分析过程的时序图摆出来:时序图-SpringBoot2.10启动分析 二.源码分析 首...

Jacktanger
49分钟前
3
0
小白带你认识netty(二)之netty服务端启动(上)

上一章 中的标准netty启动代码中,ServerBootstrap到底是如何启动的呢?这一章我们来瞅下。 server.group(bossGroup, workGroup);server.channel(NioServerSocketChannel.class).optio...

天空小小
今天
3
0
聊聊storm trident batch的分流与聚合

序 本文主要研究一下storm trident batch的分流与聚合 实例 TridentTopology topology = new TridentTopology(); topology.newStream("spout1", spout) .p......

go4it
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部