• spring 事件监听器的使用及事件异步处理


    spring 中的事件监听机制是运用观察者模式来实现的,观察者模式的优点有:

    1、观察者和被观察者之间低耦合,代码比较好维护

    2、被观察者和观察者之间是一对多的关系(当然也可以一对一),当被观察者状态改变的时候,多个观察者能同时进行处理,能实现广播通讯

    观察者模式有两种角色:

    1、Subject 目标角色:接收外界的状态变化,向观察者发送通知(广播通知)        

    2、Observer 观察者角色:就是具体操作的一个实体,根据Subject状态变化,会触发自身的具体操作逻辑

    所以说subject  和 observer之间是一对多的关系

     现在我们用spring监听机制来实现上述图示:

    observer1,observer2,observer3监听subject1的状态变化

    observer3,observer4监听subject2的状态变化

    可见observer3同时可以监听subject1,subject2的状态变化

    Subject1:声明事件1,Object source是通信传输数据的实体
    1. /**
    2. * @Author yangcai
    3. * @create 2022/6/24 15:47
    4. */
    5. public class Subject1 extends ApplicationEvent {
    6. public Subject1(Object source) {
    7. super(source);
    8. }
    9. }
    Subject2:声明事件2,Object source是通信传输数据的实体
    1. /**
    2. * @Author yangcai
    3. * @create 2022/6/24 15:47
    4. */
    5. public class Subject2 extends Subject1 {
    6. public Subject2(Object source) {
    7. super(source);
    8. }
    9. }
    EventPublisher:事件发布器,给监听器发送通知,触发监听器的执行
    1. @Component
    2. @Slf4j
    3. public class EventPublisher implements ApplicationEventPublisherAware {
    4. private ApplicationEventPublisher eventPublisher;
    5. public void publish(ApplicationEvent event) {
    6. eventPublisher.publishEvent(event);
    7. }
    8. @Override
    9. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    10. this.eventPublisher = applicationEventPublisher;
    11. }
    12. }

     

    1. @Data
    2. public class SourceEntity {
    3. private String subjectName;
    4. private String notifyMsg;
    5. }

     ObserverEventHandler 声明监听器及监听的事件,多个监听器可以监听一个事件

    1. /**
    2. * @Author yangcai
    3. * @create 2022/6/24 15:48
    4. */
    5. @Slf4j
    6. @Component
    7. @RequiredArgsConstructor
    8. public class ObserverEventHandler {
    9. @EventListener(id="observer1",condition = "@listenerPredicate.test(#event)")
    10. public void handle1(Subject1 event) {
    11. SourceEntity sourceEntity = (SourceEntity)event.getSource();
    12. log.info("--observer1---handle1-----"+sourceEntity.getSubjectName());
    13. }
    14. @EventListener(id="observer2",condition = "@listenerPredicate.test(#event)")
    15. public void handle2(Subject1 event) {
    16. SourceEntity sourceEntity = (SourceEntity)event.getSource();
    17. log.info("--observer2---handle2-----"+sourceEntity.getSubjectName());
    18. }
    19. @EventListener(id="observer3")
    20. public void handle3(Subject1 event) {
    21. SourceEntity sourceEntity = (SourceEntity)event.getSource();
    22. log.info("--observer3---handle3-----"+sourceEntity.getSubjectName());
    23. }
    24. @EventListener(id="observer4")
    25. public void handle4(Subject2 event) {
    26. SourceEntity sourceEntity = (SourceEntity)event.getSource();
    27. log.info("--observer4---handle4-----"+sourceEntity.getSubjectName());
    28. }
    29. }

    监听器监听事件的条件匹配器,可以根据通信实体中的数据,当事件被发布时,来进行判断当前监听器是否会触发执行

    1. /**
    2. * @Author yangcai
    3. * @create 2022/6/28 16:20
    4. */
    5. @Component
    6. public class ListenerPredicate implements Predicate<ApplicationEvent> {
    7. @Override
    8. public boolean test(ApplicationEvent event) {
    9. SourceEntity sourceEntity = (SourceEntity)event.getSource();
    10. if(event instanceof Subject2 && "subject2".equals(sourceEntity.getSubjectName())){
    11. return false;
    12. }
    13. return true;
    14. }
    15. }

    测试subject1: 

    1. @SpringBootApplication
    2. public class Stu1Application {
    3. public static void main(String[] args) throws InterruptedException {
    4. ApplicationContext ac = SpringApplication.run(Stu1Application.class, args);
    5. SubjectPublisher eventPublisher = ac.getBean(SubjectPublisher.class);
    6. SourceEntity sourceEntity = new SourceEntity();
    7. sourceEntity.setSubjectName("subject1");
    8. eventPublisher.publish(new Subject1(sourceEntity));
    9. }
    10. }

     ​​​结果:

     测试subject2: 

    1. @SpringBootApplication
    2. public class Stu1Application {
    3. public static void main(String[] args) throws InterruptedException {
    4. ApplicationContext ac = SpringApplication.run(Stu1Application.class, args);
    5. SubjectPublisher eventPublisher = ac.getBean(SubjectPublisher.class);
    6. SourceEntity sourceEntity = new SourceEntity();
    7. sourceEntity.setSubjectName("subject2");
    8. eventPublisher.publish(new Subject2(sourceEntity));
    9. }
    10. }

      ​​​结果:

     配置监听器异步执行:需要新增两个配置文件

    1. /**
    2. * @Author yangcai
    3. * @create 2022/6/24 15:57
    4. */
    5. @Configuration
    6. public class ApplicationEventAsyncConfig {
    7. @Resource
    8. private ThreadPoolTaskExecutor myExecutor;
    9. @Bean
    10. public ApplicationEventMulticaster applicationEventMulticaster() { //@1
    11. //创建一个事件广播器
    12. SimpleApplicationEventMulticaster result = new SimpleApplicationEventMulticaster();
    13. //设置异步执行器,来完成异步执行监听事件这样会导致所有的监听器都异步执行
    14. result.setTaskExecutor(myExecutor);
    15. return result;
    16. }
    17. }
    1. @Configuration
    2. public class ThreadPoolConfig {
    3. @Bean("myExecutor")
    4. public Executor taskExecutor() {
    5. ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    6. //设置线程池参数信息
    7. taskExecutor.setCorePoolSize(8);
    8. taskExecutor.setMaxPoolSize(20);
    9. taskExecutor.setQueueCapacity(50);
    10. taskExecutor.setKeepAliveSeconds(60);
    11. taskExecutor.setThreadNamePrefix("eventHandle--");
    12. taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    13. // 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
    14. taskExecutor.setAwaitTerminationSeconds(60);
    15. //修改拒绝策略为使用当前线程执行
    16. taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    17. //初始化线程池
    18. taskExecutor.initialize();
    19. return taskExecutor;
    20. }
    21. }

     

  • 相关阅读:
    Html5的新增特性
    UNIX环境高级编程-第一章
    Java程序设计-韩建平-读书笔记
    基于布谷鸟优化K均值的WSN分簇路由算法
    HC32_HC32F072FAUA_FLASH使用
    【博客486】prometheus-----rate,irate,increase的原理
    JAVA毕业设计html5健身房信息管理系统计算机源码+lw文档+系统+调试部署+数据库
    java-net-php-python-jspm招警考试模拟题库计算机毕业设计程序
    kanzi案例Coin
    使用 ClickHouse 深入了解 Apache Parquet (一)
  • 原文地址:https://blog.csdn.net/beiduofen2011/article/details/125503129