目前的版本是spring 4.3.10 release版,这里的@Transcational注解是spring的注解,而不是javax.persitence的注解html
通常而言,事件的生命周期为事件建立, 事件发布,事件订阅,事件结束.java
spring的事件都继承ApplicationEvent,而后添加本身须要的东西spring
以下:数组
public class LoginEvent extends ApplicationEvent implements PointCommon { public LoginEvent(Object source) { super(source); } private String activeId; private String activeCode="login"; private Boolean pointFlag; public String getActiveId() { return activeId; } public void setActiveId(String activeId) { this.activeId = activeId; } @Override public String getActiveCode() { return activeCode; } public Boolean getPointFlag() { return pointFlag; } public void setPointFlag(Boolean pointFlag) { this.pointFlag = pointFlag; } public LoginEvent(Object source, String activeId, String activeCode, Boolean pointFlag) { super(source); this.activeId = activeId; this.pointFlag = pointFlag; } }
这是一个自定的登陆事件,定义了基本的事件信息.架构
通常实现ApplicationEventPublisherAware,使用 ApplicationEventPublisher publisher来发布事件. 自定义事件app
public class LoginService implements ApplicationEventPublisherAware { private EventService eventService; private ApplicationEventPublisher eventPublisher; @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.eventPublisher = applicationEventPublisher; } public void login(HttpServletRequest request...){ LoginEvent event = new LoginEvent("", "234sd", "login", true); publisher.publishEvent(event); } }
实现ApplicationListener<T>接口,T可指定事件的类型,可是要继承ApplicationEvent才行;异步
@Component public class PointHandler implements ApplicationListener<LoginEvent >{ @Override public void onApplicationEvent(LoginEvent event) { ... } }
这样就能够处理事件了.jvm
与下面的方式相比,继承EventListener比较笨重.async
@EventListener public void handle(PointCommon event) { out.println("----斯蒂芬-----"); out.println(event.getDescription()); }
没错,直接加上@EventListener就能实现了监听器的功能.ide
事件链中同步事件方法出现异常,整个事件链就会出现中断.不继续执行.异步方法无影响.
当全部的时间监听器处理完事件以后,事件才算结束,jvm才会执行其余操做.但有异步事件监听器时,只要全部的同步事件监听器处理完事件以后,jvm就会执行其余操做,且异步事件不会对事件源方法产生有效影响.这里能够认为事件已经结束了.
咱们能够经过注解的condition属性来添加额外的运行时拦截条件,该属性定义了一个SpEL表达式,你须要匹配这个特定事件,才能调用相应的方法.
例如,咱们的通知器能够重写为只有当事件的test属性等于foo时才会调用.
@EventListener(condition = "#event.test == 'foo'") public void processBlackListEvent(BlackListEvent event) { // notify appropriate parties via notificationAddress... }
每一次SpEL表达式评估都有专门的上下文.下面的表格展现了你在该上下文中能得到的选项,全部你可使用他们进行有条件的事件处理:
名称:event 位置:root object 描述:实际的ApplicationEvent(应用事件),例子:#root.event
名称:args 位置:root Object 描述:调用目标使用的参数(数组) 例子:#root.args[0]
名称:argument name 位置:evaluation context 描述:方法中每一个参数的名字.若是因某些缘由这些名字不可得到,这个参数的名称仍能够经过#a<#arg>来获取,这个#arg表明的是参数的下标(从0开始). 例子:#iban或#a0(也可使用#p0或使用#p<#arg>标志做为别名)
记住#root.event容许你访问对应的事件,即便你的方法签名实际上对应的是任意要发布的对象.
若是你由于处理完某个事件后须要发布一个新事件,只须要把方法签名的返回修改成你须要发布的事件的类型,像这样:
@EventListener public ListUpdateEvent handleBlackListEvent(BlackListEvent event) { // notify appropriate parties via notificationAddress and // then publish a ListUpdateEvent... }
该功能不支持异步的监听器;
这个新方法会为每一个该方法处理过的blackListEvent发布一个新的ListUpdateEvent事件.若是你须要发布几个事件,只须要返回这些事件的集合.
异步事件处理方法不支持该特性.
若是你想要一个特别的监听器来异步处理事件,简单的使用常规的@Async支持:
@EventListener @Async public void processBlackListEvent(BlackListEvent event) { // BlackListEvent is processed in a separate thread }
记住使用异步事件时注意如下几个局限:
若是你想要一个监听器先于其余调用.只须要在方法参数上添加@Order注解;
@EventListener @Order(42) public void processBlackListEvent(BlackListEvent event) { // notify appropriate parties via notificationAddress... }
你可使用泛型更深刻的定义你的事件的结构.思考一个EntityCreatedEvent<T>,其中T是被建立实体的实际类型.你能够建立一个只用来接受Person类的EntityCreatedEvent事件监听器;
@EventListener public void onPersonCreated(EntityCreatedEvent<Person> event) { ... }
因为类型擦除,只有当事件无缺符合事件监听器拦截的泛型参数,它才工做.(这相似如class PersonCreatedEvent extends EntityCreatedEvent<Person>{...});
在特定的环境下,若是有全部的事件都遵循相同的结构(它多是上面提到的那种事件)会变得至关乏味.这样的话,你可用实现ResolvableTypeProvider来指导运行时环境提供的架构.
public class EntityCreatedEvent<T> extends ApplicationEvent implements ResolvableTypeProvider { public EntityCreatedEvent(T entity) { super(entity); } @Override public ResolvableType getResolvableType() { return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getSource())); } }
它不只只对ApplicationEvent事件其做用,还适用于你做为事件发布的包含着的任意对象.
spring的默认事件是同步事件.
@EventListener @Transactional public void handleEvent(EventEvent event) { throw new NullPointerException("测试事务"); // System.out.println("同步步处理问题!!"); }
若是方法上加事务注解,则对其方法的事务其做用,如异常回滚.
若是方法上不加事务注解,则对其调用方法的事务无影响
若是方法加上事务注解,根据事务一致性和Transcational的默认事务传播机制,则将该事务纳入到上级方法的事务中,从而影响上级方法的事务.
开启spring异步支持,才能使用异步事件.开启方法:http://www.javashuo.com/article/p-qvvkxcsr-hd.html
经典代码例子:
@EventListener @Async @Transactional public void handleEvent2(EventEvent event) throws Exception { Event event1 = event.getEvent(); event1.setName("异步事件事务一致性"); eventService.update(event1); System.out.println("异步输出问题!!"); throw new NullPointerException("测试空指针"); }