Spring中ApplicationEventPublisher发布订阅模式的实现

 更新时间:2023年07月25日 11:49:41   作者:小白的救赎  
本文主要介绍了Spring中ApplicationEventPublisher发布订阅模式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

概念

关于发布订阅这个词,其实不仅仅出现在Spring框架当中,其实在Redis中也有存在(其对应的是convertAndSend()方法),还有在MQ消息队列里也是有的,但这里就主要介绍的是关于Spring框架的ApplicationEventPublisher如何做到消息的发布与订阅。随着现在的业务量和需求量越来越大,其实基本都是分布式微服务集群的使用了,所以基本都是用到Redis与MQ。但是对于单体Spring Boot应用时,用Spring自带的发布订阅就已经绰绰有余了。

需要知道的是发布订阅需要有三个对象:事件事件发布源事件接收源(监听器)

事件

对于事件来说,需要去继承ApplicationEvent。至于为什么需要继承ApplicationEvent就需要研究源码,等我后续看完再回来更新笔记。

public class LogEvent extends ApplicationEvent {
    public LogEvent(Object message) {
        super(message);
    }
}

事件发布源

这个基本上都是业务层的代码,但是作为学习阶段,我将其直接放在控制层。关于如何去发布,就需要用到Spring中的ApplicationEventPublisher。

@Slf4j
@RestController
@RequestMapping("/log")
public class LogController {
    @Autowired
    private ApplicationEventPublisher publisher;
    @GetMapping("/publisher")
    public void log() {
        log.info("进入到log方法,开始发送事件");
        publisher.publishEvent(new LogEvent("log方法生成事件信息"));
        log.info("log方法发送事件完毕");
    }
}

监听器

/**
 * 管理员日志监听器
 */
@Slf4j
@Component
public class AdminListener {
    @EventListener(LogEvent.class)
    public void adminListen(LogEvent logEvent) {
        try {
            log.info("管理员监听到的日志信息为,{}", logEvent);
            Thread.sleep(5000); // 睡眠5s
            log.info("管理员监听完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
 * 用户日志事件监听器
 */
@Slf4j
@Component
public class UserListener {
    @EventListener(LogEvent.class)
    public void userListen(LogEvent logEvent) {
        try {
            log.info("用户监听到的日志信息为,{}", logEvent);
            Thread.sleep(10000); // 睡眠10s
            log.info("用户监听完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果

从执行结果可以发现管理员线程睡眠了5s后执行完毕才会执行用户的代码块。所以表明是同步执行的。

于是为了将同步执行变为异步执行,又在两个监听器的方法上添加了@Async注解,并且一定要在启动类上添加@EnableAsync注解。再次执行会发现两次的执行结果并不一致。两个监听器是异步执行的。甚至在监听器上放置@Order注解可以实现先后顺序,但这里就不演示了。

源码追踪

这里只进行粗略的源码查看,因为作者功力有限无法解释得完全仔细,以后看懂了再回来更新笔记。可以发现其已经使用了JDK8新特性了。从ApplicationEventPublisher的publisher(Application event)方法就会进入到其子类AbstartApplicationContext中。

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");
        Object applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent)event;
        } else {
            applicationEvent = new PayloadApplicationEvent(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType();
            }
        }
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        } else {
            // 在这步完成真正的发布订阅 只有监听完才会向下继续执行
            this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType);
        }
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext)this.parent).publishEvent(event, eventType);
            } else {
                this.parent.publishEvent(event);
            }
        }

到此这篇关于Spring中ApplicationEventPublisher发布订阅模式的实现的文章就介绍到这了,更多相关Spring ApplicationEventPublisher发布订阅模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring解决循环依赖问题的三种方法小结

    Spring解决循环依赖问题的三种方法小结

    在 Spring 中,循环依赖问题指的是两个或多个 bean 之间相互依赖形成的闭环,具体而言,当 bean A 依赖于 bean B,同时 bean B 也依赖于 bean A,就形成了循环依赖,本文就给大家介绍了Spring解决循环依赖问题的三种方法,需要的朋友可以参考下
    2023-09-09
  • SpringBoot整合RabbitMQ, 实现生产者与消费者的功能

    SpringBoot整合RabbitMQ, 实现生产者与消费者的功能

    这篇文章主要介绍了SpringBoot整合RabbitMQ, 实现生产者与消费者的功能,帮助大家更好得理解和学习使用SpringBoot框架,感兴趣的朋友可以了解下
    2021-03-03
  • SWT(JFace)体验之StyledText类

    SWT(JFace)体验之StyledText类

    有的时候Text需要实现这种那种的样式。先提供在不使用StyledText类的情况:
    2009-06-06
  • 如何使用Collections.reverse对list集合进行降序排序

    如何使用Collections.reverse对list集合进行降序排序

    这篇文章主要介绍了Java使用Collections.reverse对list集合进行降序排序,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java基础之简单的图片处理

    Java基础之简单的图片处理

    这篇文章主要介绍了Java基础之简单的图片处理,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Mybatis中 mapper-locations和@MapperScan的作用

    Mybatis中 mapper-locations和@MapperScan的作用

    这篇文章主要介绍了Mybatis中 mapper-locations和@MapperScan的作用,mybatis.mapper-locations在SpringBoot配置文件中使用,作用是扫描Mapper接口对应的XML文件,需要的朋友可以参考下
    2023-05-05
  • MyBatis之自动映射与缓存问题及解析

    MyBatis之自动映射与缓存问题及解析

    文章主要介绍了MyBatis的配置与操作,包括自动映射(autoMappingBehavior)的设置(NONE、PARTIAL、FULL)、手动映射的步骤(使用<resultMap>标签)、SQL注入攻击的原理、缓存机制及其影响(一级缓存和二级缓存的作用、缓存失效的情况)
    2025-09-09
  • java基础之字符串编码知识点总结

    java基础之字符串编码知识点总结

    这篇文章主要介绍了java基础之字符串编码总结,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有很好的帮助,要的朋友可以参考下
    2021-04-04
  • 详解java中&和&&的区别

    详解java中&和&&的区别

    这篇文章主要介绍了java中&和&&的区别,在java中比较常见的运算符:&&(短路与)、&、||(短路或)、|,需要的朋友可以参考下
    2015-07-07
  • MyBatis实现留言板的示例代码

    MyBatis实现留言板的示例代码

    本文主要介绍了MyBatis实现留言板的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08

最新评论