我们知道观察者模式可以实现代码的解耦,而spring的event模型就是这种设计模式的极佳体现。一个事件包含:事件发布、监听、和事件源。在spring中我们可以通过ApplicationContext的publishEvent方法去发布事件;通过实现实现ApplicationListener接口来自定义自己的监听器;继承ApplicationEvent类来实现事件源。下面以一个实例来说明:
1.spring下使用event模型
1.1 定义event
/**
* event的基类
*
* @author 94977
* @create 2018/7/22
*/
public abstract class BaseEvent extends ApplicationEvent {
private static final long serialVersionUID = 895628808370649881L;
public BaseEvent(Object source) {
super(source);
}
}
public class FaceEvent extends BaseEvent {
private static final long serialVersionUID = -6574102695264647771L;
/**
* @author 94977
* @time 2018/7/22 15:50
* @param * @param null
* @return
* @description 必须要实现的构造方法
*/
public FaceEvent(User user) {
super(user);
}
}
1.2 event的监听处理类。监听类实现ApplicationListener 里onApplicationEvent方法即可
@Component
public class FaceEventListener extends BaseEventListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof FaceEvent){
User user = (User) event.getSource();
LOGGER.info("===> 收到人脸事件: {}",user);
// .....
System.out.println("人脸事件处理结束。。。");
}
}
}
当然通过event instanceof FaceEvent判断事件源来处理的方式不是很优雅。有更好的方式,接口ApplicationListener支持泛型,可以通过泛型来判断处理的事件源。如下只处理FaceEvent源。
@Component
public class FaceEventListener extends BaseEventListener implements ApplicationListener<FaceEvent> {
@Override
public void onApplicationEvent(FaceEvent event) {
User user = (User) event.getSource();
LOGGER.info("===> 收到人脸事件: {}",user);
// .....
System.out.println("人脸事件处理结束。。。");
}
}
1.3 发布事件
@Service
public class FaceHandler {
@Autowired
private ApplicationContext applicationContext;
public void handle(){
User user = new User();
user.setAge(34);
user.setUsername("人脸事件");
user.setHobby("抓拍");
//发布事件
applicationContext.publishEvent(new FaceEvent(user));
//进行其他业务处理
}
以上即可。
1.4 如果要实现有序的监听,方式如下:即实现SmartApplicationListener 接口即可。
@Component
public class FaceEventListener2 extends BaseEventListener implements SmartApplicationListener {
/**
* @description 用于指定支持的事件类型,只有支持的才调用onApplicationEvent;
*/
@Override
public boolean supportsEventType(final Class<? extends ApplicationEvent> eventType) {
return eventType == FaceEvent.class;
}
/**
* @description supportsSourceType:支持的目标类型,只有支持的才调用onApplicationEvent;
*/
@Override
public boolean supportsSourceType(final Class<?> sourceType) {
return sourceType == String.class;
}
@Override
public void onApplicationEvent(final ApplicationEvent event) {
System.out.println("收到内容:" + event.getSource());
}
/**
* 即顺序,越小优先级越高
*/
@Override
public int getOrder() {
return 2;
}
}
2.evnet模型的关键点
- 事件没要处理的监听器,就会被抛弃。
- 一个事件可以同时被多个监听处理类监听处理。
- 以上处理事件都是同步的,如果发布事件处的业务存在事务,监听器处理也会在相同的事务中。这个一定要注意!如果对于事件的处理不想受到影响,可以onApplicationEvent方法上加@Aync支持异步。
- 原理部分可以参考 博客 事件体系
3. 异步方法的实现
在spring中,通过在方法上添加注解@Async,可以通过executor完成异步处理此方法。注意还要添加@EnableAsync来开启异步任务的支持。
如果不自定义线程池,会使用spring的默认Executor,我们可以自定义线程池。
@Configuration
public class TaskExecutorConfig {
@Bean("TaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(5);
taskExecutor.setMaxPoolSize(15);
taskExecutor.setQueueCapacity(6000);
taskExecutor.initialize();
return taskExecutor;
}
}