准备三个部分
事件类:定义事件,继承ApplicationEvent的类成为一个事件类。
发布者:发布事件,通过ApplicationEventPublisher发布事件。
监听者:监听并处理事件,实现ApplicationListener接口或者使用@EventListener注解。
事件类
只要继承org.springframework.context.ApplicationEvent,便是一个Spring Event类。
一般我们会专门为一个类型的Event写一个抽象的事件类,作为该类型的所有事件的父类
方法一:定义一个抽象的事件类的父类
/**
* 账户相关的事件
*/
public abstract class AccountEvent extends ApplicationEvent {
/**
* 该类型事件携带的信息
*/
private AccountEventData eventData;
/**
*
* @param source 最初触发该事件的对象
* @param eventData 该类型事件携带的信息
*/
public AccountEvent(Object source, AccountEventData eventData) {
super(source);
this.eventData = eventData;
}
public AccountEventData getEventData() {
return eventData;
}
}
/**
* 推荐使用类实现的方式来发布具体的事件,
* 而不是在事件中使用private String eventType定义事件的类型,
* 监听器只要监听具体的事件类即可,而无需再做判断,同时也不需要再另外维护事件类型列表。
*/
public class AccountCreatedEvent extends AccountEvent {
public AccountCreatedEvent(Object source, AccountEventData eventData) {
super(source, eventData);
}
}
方法二:泛型定义一个统一的父类
public abstract class BaseEvent<T> extends ApplicationEvent {
/**
* 该类型事件携带的信息
*/
private T eventData;
/**
*
* @param source 最初触发该事件的对象
* @param eventData 该类型事件携带的信息
*/
public BaseEvent(Object source, T eventData) {
super(source);
this.eventData = eventData;
}
public T getEventData() {
return eventData;
}
}
public class AccountCreatedEvent extends BaseEvent<AccountEventData> {
public AccountCreatedEvent(Object source, AccountEventData eventData) {
super(source, eventData);
}
}
public class TodoCreatedEvent extends BaseEvent<TodoEventData> {
public TodoCreatedEvent(Object source, TodoEventData eventData) {
super(source, eventData);
}
}
发布事件
发布者负责发布消息,有三种实现方式。
Spring容器中默认的ApplicationEventPublisher是AbstractApplicationContext,同时AbstractApplicationContext也是ApplicationContext的一个子类,也就是说,Spring默认使用AbstractApplicationContext发布事件。
方式1:直接使用ApplicationEventPublisher(推荐)
import org.springframework.context.ApplicationEventPublisher;
public class AccountsController {
@Autowired
private ApplicationEventPublisher publisher;
@PostMapping("")
public Account createAccount(@RequestBody Account account) {
...
publisher.publishEvent(new AccountCreatedEvent(this, new AccountEventData()));
return account;
}
}
方式2:实现ApplicationEventPublisherAware接口(推荐)
public interface ApplicationEventPublisherAware extends Aware {
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
package org.springframework.data.rest.webmvc;
@RepositoryRestController
class RepositoryEntityController extends AbstractRepositoryRestController implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
private ResponseEntity<ResourceSupport> saveAndReturn(Object domainObject, RepositoryInvoker invoker,
HttpMethod httpMethod, PersistentEntityResourceAssembler assembler, boolean returnBody) {
publisher.publishEvent(new BeforeSaveEvent(domainObject));
Object obj = invoker.invokeSave(domainObject);
publisher.publishEvent(new AfterSaveEvent(obj));
...
}
...
}
监听事件
方法一:实现ApplicationListener接口或
方法二:使用@EventListener注解(推荐)
可以使用@EventListener在同一个类中用不同的方法监听多个不同的事件。相对于实现ApplicationListener接口,使用@EventListener会更加灵活。
@Slf4j
@Component
public class SyncAccountListener {
/**
* 异步发送邮件
* @param event
*/
@EventListener
public void doOnNormalEvent(NormalAccountEvent event) {
try {
log.debug("befor");
Thread.sleep(1000);
log.debug("after");
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
}
}
@EventListener(value = {AccountCreatedEvent.class, AccountUpdatedEvent.class}, condition = "#event.account.age > 10")
public void doSomethingOnAccountEvent(AccountEvent event) {
// TODO
}
value: 监听的事件(组),用于支持同一父类的事件
class: 同value
condition: SpEL,使得Event Handler变得conditional
#root.event, Application的引用
#root.args, 表示方法参数,#root.args[0]表示第0个方法参数
#<name>, 如上面代码中的#event表示以参数名关联参数