ApplicationEvent
以及Listener
是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。
创建Event事件
java
public class MessageEvent extends ApplicationEvent {
/**
* 消息体
*/
private MessageDTO messageDTO;
/**
* Create a new ApplicationEvent.
*
* @param source the object on which the event initially occurred (never {@code null})
*/
public MessageEvent(MessageDTO source) {
super(source);
this.messageDTO = source;
}
public MessageDTO getMessageDTO() {
return messageDTO;
}
}
我们自定义事件MessageEvent继承了ApplicationEvent,继承后必须重载构造函数,构造函数的参数可以任意指定,其中source参数指的是发生事件的对象,该对象可以在监听内被获取。
在Spring内部中有多种方式实现监听如:@EventListener注解、实现ApplicationListener泛型接口、实现SmartApplicationListener接口等,我们下面来讲解下这三种方式分别如何实现。
创建MessageDTO
java
public class MessageDTO {
/**
* 消息类型
*/
private MsgTypeEnum msgType;
/**
* 消息发出时的时间戳
*/
private Long syncTime;
}
事件发布
java
@Service
public class UserService
{
@Autowired
ApplicationContext applicationContext;
public void register()
{
//../省略其他逻辑
//发布事件
applicationContext.publishEvent(new MessageEvent(new MessageDTO()));
}
}
事件发布是由ApplicationContext对象管控的,我们发布事件前需要注入ApplicationContext对象调用publishEvent方法完成事件发布。
实现监听
@EventListener
java
@Service
public class MessageEventService {
@EventListener
public void notify(MessageEvent messageEvent) {
log.info("异步发送消息体:{}", JSON.toJSONString(messageEvent));
}
}
ApplicationListener
java
@Component
public class RegisterListener implements ApplicationListener<MessageEvent>
{
/**
* 实现监听
*/
@Override
public void onApplicationEvent(MessageEvent messageEvent) {
}
}
SmartApplicationListener实现有序监听
java
@Component
public class UserRegisterListener implements SmartApplicationListener
{
/**
* 该方法返回true&supportsSourceType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass 接收到的监听事件类型
* @return
*/
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
//只有MessageEvent监听类型才会执行下面逻辑
return aClass == MessageEvent.class;
}
/**
* 该方法返回true&supportsEventType同样返回true时,才会调用该监听内的onApplicationEvent方法
* @param aClass
* @return
*/
@Override
public boolean supportsSourceType(Class<?> aClass) {
//只有在UserService内发布的MessageEvent事件时才会执行下面逻辑
return aClass == UserService.class;
}
/**
* supportsEventType & supportsSourceType 两个方法返回true时调用该方法执行业务逻辑
* @param applicationEvent 具体监听实例,这里是UserRegisterEvent
*/
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
//转换事件类型
MessageEvent messageEvent = (MessageEvent) applicationEvent;
}
/**
* 同步情况下监听执行的顺序
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
SmartApplicationListener接口继承了全局监听ApplicationListener,并且泛型对象使用的ApplicationEvent来作为全局监听,可以理解为使用SmartApplicationListener作为监听父接口的实现,监听所有事件发布。
既然是监听所有的事件发布,那么SmartApplicationListener接口添加了两个方法supportsEventType、supportsSourceType来作为区分是否是我们监听的事件,只有这两个方法同时返回true时才会执行onApplicationEvent方法。
可以看到除了上面的方法,还提供了一个getOrder方法,这个方法就可以解决执行监听的顺序问题,return的数值越小证明优先级越高,执行顺序越靠前。
如果说我们不希望在执行监听时等待监听业务逻辑耗时,发布监听后立即要对接口或者界面做出反映,我们该怎么做呢?
使用@Async实现异步监听
@Aysnc其实是Spring内的一个组件,可以完成对类内单个或者多个方法实现异步调用,这样可以大大的节省等待耗时。内部实现机制是线程池任务ThreadPoolTaskExecutor,通过线程池来对配置@Async的方法或者类做出执行动作。
线程任务池配置
我们创建一个ListenerAsyncConfiguration,并且使用@EnableAsync注解开启支持异步处理,具体代码如下所示:
java
@Configuration
@EnableAsync
public class ListenerAsyncConfiguration implements AsyncConfigurer
{
/**
* 获取异步线程池执行对象
* @return
*/
@Override
public Executor getAsyncExecutor() {
//使用Spring内置线程池任务对象
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//设置线程池参数
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(10);
taskExecutor.setQueueCapacity(25);
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
我们自定义的监听异步配置类实现了AsyncConfigurer接口并且实现内getAsyncExecutor方法以提供线程任务池对象的获取。
我们只需要在异步方法上添加@Async注解就可以实现方法的异步调用
java
@Service
public class MessageEventService {
@EventListener
@Async
public void notify(MessageEvent messageEvent) {
log.info("异步发送消息体:{}", JSON.toJSONString(messageEvent));
}
}