spring中ApplicationListener的使用小结
作者:孟秋与你
ApplicationListener 是spring提供的一个监听器,它可以实现一个简单的发布-订阅功能,用有点外行但最简单通俗的话来解释:监听到主业务在执行到了某个节点之后,在监听器里面做出相应的其它业务变更。下面我们具体看段代码,则能很快的理解
使用示例:
首先定义一个业务实体类,实体类定义字段、get set方法、构造函数
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor /** * 模拟业务对象实体类 * @author csdn:孟秋与你 */ public class MyBizEntity { private String name; private Integer age; }
再定义一个事件,事件继承ApplicationEvent
import org.springframework.context.ApplicationEvent; /** * 自定义事件(继承ApplicationEvent) * @author csdn:孟秋与你 */ public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } public MyEvent() { // java基础:如果父类只有有参构造 子类需要使用其它构造函数 必须在构造函数第一行调用super 因为子类也是调用父类的构造函数 super(null); // do other } }
定义一个监听器,实现ApplicationListener接口:
import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component; /** * 监听事件 */ @Component public class MyApplicationListener implements ApplicationListener { @Override public void onApplicationEvent(ApplicationEvent applicationEvent) { // 必须判断自己要的类型 因为会监听到所有继承ApplicationEvent的事件 if (applicationEvent instanceof MyEvent) { Object source = applicationEvent.getSource(); MyBizEntity bizEntity = (MyBizEntity) source; System.out.println(bizEntity.getName() + ":------------name"); } } }
写一个接口进行测试, 此时监听器就能打印输出了
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RequestMapping("/test/listener") @RestController public class MainBizController { @Autowired private ApplicationContext context; @GetMapping public String test() { // do something // 模拟要传递的业务对象 MyBizEntity bizEntity = new MyBizEntity("name",18); MyEvent event = new MyEvent(bizEntity); // 上下文 发布事件 context.publishEvent(event); return "success"; } }
原理简析:
为什么发布了事件,监听器就能够监听到呢? 其实原理很简单,就是spring进行了一个朴实无华的直接调用, 我们来看看源码:
context.publishEvent默认是调用AbstractApplicationContext类的publishEvent方法,而publishEvent方法里面调用了SimpleApplicationEventMulticaster 类的multicastEvent方法。
tips: 为什么上下文有publishEvent方法 ?
因为ApplicationContext继承了ApplicationEventPublisher
SimpleApplicationEventMulticaster: 首先会获取所有实现了ApplicationListener的监听器 (get by type就可以获取到), 接着会执行 invokeListener方法
我们看看最后doInvokeListener 做了什么:
通过上面源码链路,我们不难发现 其实就是调用了publishEvent方法后,spring在我们不轻易能看到的地方 去调用了一下监听器的onApplicationEvent 方法而已,通过源码我们也可以看到 默认是同步调用(没有定义taskExecutor时), 本质上是一个解耦,把原本可能要写在一起的业务代码拆分了。
如何异步发送
通过源码可以看到 SimpleApplicationEventMulticaster类的multicastEvent方法,会先获取Executor ,如果有executor 则通过异步方式发送
所以问题就变成了这个executor如何才能获取到值。
可以看到该类有一个public的setTaskExecutor方法
所以我们可以直接将该类的实例作为一个bean给spring托管,代码如下
@Configuration public class EventConfig { @Bean(name = "applicationEventMulticaster") public SimpleApplicationEventMulticaster simpleApplicationEventMulticaster(TaskExecutor taskExecutor) { SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster(); eventMulticaster.setTaskExecutor(taskExecutor); return eventMulticaster; } }
这里涉及到一个spring的基础知识,上面代码的参数是(TaskExecutor taskExecutor) 所以需要先有一个executor bean,代码示例如下:
@Configuration public class AsyncInBootConfig { /** 核心线程池大小 */ private int corePoolSize = 20; /** * 最大可创建的线程数 */ private int maxPoolSize = 50; /** * 队列最大长度 */ private int queueCapacity = 100; /** * 线程池维护线程所允许的空闲时间 */ private int keepAliveSeconds = 300; @Primary @Bean(name = "threadPool") /** * springboot 线程池方式 */ public ThreadPoolTaskExecutor threadPoolTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setMaxPoolSize(maxPoolSize); executor.setCorePoolSize(corePoolSize); executor.setQueueCapacity(queueCapacity); executor.setKeepAliveSeconds(keepAliveSeconds); // 线程池对拒绝任务(无线程可用)的处理策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
这样在发布消息时,就会使用全局配置的这个threadPool线程池了
到此这篇关于spring中ApplicationListener的使用小结的文章就介绍到这了,更多相关spring ApplicationListener内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!