前言
该文章是我学习使用SpirngEvent的过程,现在只写了SpringEvent的应用,后续会写一篇从源码关注SpringEvent的实现过程。

SpringEvent的介绍
SpringEvent在我认为是一个解决业务解耦的办法,运用了观察者模式,用于 当一个业务的更改后,需要改变其他业务的状态 。例如一个商品的下单,需要修改商品的库存,以及商家的消息发送等等。之前我做这种业务解耦的时候,使用的时消息队列进行解耦,但如果只是为了解耦而整合了消息队列,就有点大了,我认为,可以使用此方式需要满足下面的条件:
- 当做完业务的时候,不清楚有多少个子业务要进行更改,例如安防设备的报警,初期可能只是发送消息到持有设备的用户,页面显示报警状态,后期或许会涉及到同步到其他平台业务、和其他安防设备产生连锁报警业务等等。
SpringEvent的应用
环境配置
JDK8
Spring boot 2.6.10
业务场景
当电脑启动的时候,电脑的自启程序需要启动,程序的服务也需要启动等等。
实现
创建ComputerStartEvent电脑启动事件类
/** * 电脑启动事件类 */public class ComputerStartEvent extends licationEvent { private ComputerEntity computerEntity; public ComputerEntity getComputerEntity() { return computerEntity; } public ComputerStartEvent(ComputerEntity source) { super(source); this.computerEntity=source; }}复制代码
创建AutoStartupSoftwareListener自启软件启动监听类
/**** 自启软件启动监听类*/@Componentpublic class AutoStartupSoftwareListener implements ApplicationListener<ComputerStartEvent> { @Override public void onApplicationEvent(ComputerStartEvent event) { ComputerEntity computer=event.getComputerEntity(); System.out.println("电脑"+computer.getName()+"的自启软件正在进行"); }}复制代码
创建ProgramServiceStartupListener程序服务启动监听类
/** * 程序服务启动监听类 */@Componentpublic class ProgramServiceStartupListener implements ApplicationListener<ComputerStartEvent> { @Override public void onApplicationEvent(ComputerStartEvent event) { ComputerEntity computer=event.getComputerEntity(); System.out.println("电脑"+computer.getName()+"的程序服务正在启动"); }}复制代码
客户端代码
poublic class ComputerService { @Resource private ApplicationEventPublisher applicationEventPublisher; public void computerStart() { ComputerEntity computer=new ComputerEntity();; computer.setComputerId("dafdasf"); computer.setName("电脑A"); // 电脑启动操作 System.out.println(computer.getName()+"电脑启动了"); //发布电脑启动事件 applicationEventPublisher.publishEvent(new ComputerStartEvent(computer)); }}复制代码
效果
异步实现
目前有两种方式可以实现异步,
- 一种是使用@EnableAsync和@Async启动异步。
- 一种是给Springboot的默认实现 SimpleAsyncEventMulticaster 类中的 taskExecutor 字段赋值一个线程池。
一、使用@EnableAsync和@Async启动异步
下面为了演示异步的效果,自启软件的监听类不使用异步,程序服务的监听类使用异步,然后每个方法打印当前线程的Id。
AutoStartupSoftwareListener自启软件启动监听类
/*** 自启软件启动监听类*/@Componentpublic class AutoStartupSoftwareListener implements ApplicationListener<ComputerStartEvent> { @Override public void onApplicationEvent(ComputerStartEvent event) { ComputerEntity computer=event.getComputerEntity(); System.out.println("电脑"+computer.getName()+"的自启软件正在进行"); //打印线程Id System.out.println("AutoStartupSoftwareListener监听线程id:"+Thread.currentThread().getId()); }}复制代码
ProgramServiceStartupListener程序服务启动监听类
/** * 程序服务启动监听类 */@EnableAsync@Componentpublic class ProgramServiceStartupListener implements ApplicationListener<ComputerStartEvent> { @Override @Async public void onApplicationEvent(ComputerStartEvent event) { ComputerEntity computer=event.getComputerEntity(); System.out.println("电脑"+computer.getName()+"的程序服务正在启动"); //打印线程Id System.out.println("ProgramServiceStartupListener监听线程id:"+Thread.currentThread().getId()); }}复制代码
客户端代码
poublic class ComputerService { @Resource private ApplicationEventPublisher applicationEventPublisher; public void computerStart() { ComputerEntity computer=new ComputerEntity();; computer.setComputerId("dafdasf"); computer.setName("电脑A"); // 电脑启动操作 System.out.println(computer.getName()+"电脑启动了"); //发布电脑启动事件 applicationEventPublisher.publishEvent(new ComputerStartEvent(computer)); //打印线程Id System.out.println("computerStart方法线程id:"+Thread.currentThread().getId()); }}复制代码
效果
异步启用成功
二、给SimpleAsyncEventMulticaster类中的taskExecutor字段赋值线程池
创建SimpleAsyncEventMulticaster继承SimpleApplicationEventMulticaster
//需要指定下beanName@Component("applicationEventMulticaster")public class SimpleAsyncEventMulticaster extends SimpleApplicationEventMulticaster { public SimpleAsyncEventMulticaster(){ ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor(); taskExecutor.initialize(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(100); taskExecutor.setQueueCapacity(1000); taskExecutor.setThreadNamePrefix("test-async"); setTaskExecutor(taskExecutor); }}复制代码
效果
两种异步的区别
如果给
SimpleAsyncEventMulticaster 的 taskExecutor 字段赋值线程池,所有监听类的执行都会是异步的,如果想要个别的任务执行是异步的话,需要重写
SimpleAsyncEventMulticaster 的 multicastEvent 方法,而使用@Async则不会,这也是为啥推荐的都是@Async方式实现异步。
总结
本文章介绍了SpringEvent和应用条件以及实例,这里没有写源码的解析,因为比较长,上述内容如果有误人子弟的地方,望在评论区留言。
胜象大百科









