180609-Spring之事件驱动机制的简单使用

简介: 关于事件的发起与相应,在客户端的交互中可算是非常频繁的事情了,关于事件的发布订阅,在Java生态中,EventBus可谓是非常有名了,而Spring也提供了事件机制,本文则主要介绍后端如何在Spring的环境中,使用事件机制

image.png

文章链接:liuyueyi.github.io/hexblog/hex…


Spring之事件驱动机制的简单使用



关于事件的发起与相应,在客户端的交互中可算是非常频繁的事情了,关于事件的发布订阅,在Java生态中,EventBus可谓是非常有名了,而Spring也提供了事件机制,本文则主要介绍后端如何在Spring的环境中,使用事件机制


I. 使用姿势



主要借助

org.springframework.context.ApplicationEventPublisher#publishEvent(org.springframework.context.ApplicationEvent) 来发布事件,而接受方,则直接在处理的方法上,添加 @@EventListener注解即可


1. 事件定义


发布一个事件,所以第一件事就是要定义一个事件,对Spring而言,要求自定义的事件继承自ApplicationEvent类, 一个简单的demo如下


public class NotifyEvent extends ApplicationEvent {
    @Getter
    private String msg;
    public NotifyEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }
}
复制代码


2. 发布事件


发布时间则比较简单,直接拿到ApplicationContext实例,执行publish方法即可,如下面给出一个简单的发布类


@Component
public class NotifyPublisher implements ApplicationContextAware {
    private ApplicationContext apc;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.apc = applicationContext;
    }
    // 发布一个消息
    public void publishEvent(int status, String msg) {
        if (status == 0) {
            apc.publishEvent(new NotifyEvent(this, msg));
        } else {
            apc.publishEvent(new NewNotifyEvent(this, msg, ((int) System.currentTimeMillis() / 1000)));
        }
    }
}
复制代码


3. 事件监听器


在方法上添加注解即可,如下


@Component
public class NotifyQueueListener {
    @EventListener
    public void consumerA(NotifyEvent notifyEvent) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("A: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }
    @EventListener
    public void consumerB(NewNotifyEvent notifyEvent) {
        System.out.println("B: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }
    @EventListener
    public void consumerC(NotifyEvent notifyEvent) {
        System.out.println("C: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }
}
复制代码


II. 疑问及解答



1. 发布与监听器的关联


上面给出了使用的姿势,看起来并不复杂,也比较容易使用,但是一个问题需要在使用之前弄明白了,发布事件和监听器是怎么关联起来的呢?


  • 根据方法的参数类型执行


那么如果发布者,推送的是一个NotifyEvent类型的事件,那么接收者是怎样的呢?


  • 参数为NotifyEvent以及其子类的监听器,都可以接收到消息


测试用例如下:


NewNotifyEvent 继承自上面的NotifyEvent

public class NewNotifyEvent extends NotifyEvent {
    @Getter
    private int version;
    public NewNotifyEvent(Object source, String msg) {
        super(source, msg);
    }
    public NewNotifyEvent(Object source, String msg, int version) {
        super(source, msg);
        this.version = version;
    }
}
复制代码


然后借助上面的消息发布者发送一个消息

@Test
public void testPublishEvent() throws InterruptedException {
    notifyPublisher.publishEvent(1, "新的发布事件! NewNotify");
    System.out.println("---------");
    notifyPublisher.publishEvent(0, "旧的发布事件! Notify");
}
复制代码


输出结果如下,对于NewNotifyEvent, 参数类型为NotifyEvent的consumerA, consumerC都可以接收到

A: main | 新的发布事件! NewNotify
C: main | 新的发布事件! NewNotify
B: main | 新的发布事件! NewNotify
---------
A: main | 旧的发布事件! Notify
C: main | 旧的发布事件! Notify
复制代码


2. 消息接收的顺序


上面消息处理是串行的,那么先后顺序怎么确定? (下面的答案不确定,有待深入源码验证!!!)


  • 先扫描到的bean先处理
  • 同一个bean中,按精确匹配,先后定义顺序进行


3. 异步消费


对于异步消费,即在消费者方法上添加一个@Async注解,并需要在配置文件中,开启


异步支持

@Async
@EventListener
public void processNewNotifyEvent(NewNotifyEvent newNotifyEvent) {
    System.out.println("new notifyevent: " + newNotifyEvent.getMsg() + " : " + newNotifyEvent.getVersion());
}
复制代码


配置支持

@Configuration
@EnableAsync
public class AysncListenerConfig implements AsyncConfigurer {
    /**
     * 获取异步线程池执行对象
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
                new DefaultThreadFactory("test"), new ThreadPoolExecutor.CallerRunsPolicy());
    }
}



相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
15 2
|
6月前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
61 0
|
3月前
|
Java 开发工具 Spring
Spring的Factories机制介绍
Spring的Factories机制介绍
68 1
|
3月前
|
消息中间件 Kafka Java
Spring 框架与 Kafka 联姻,竟引发软件世界的革命风暴!事件驱动架构震撼登场!
【8月更文挑战第31天】《Spring 框架与 Kafka 集成:实现事件驱动架构》介绍如何利用 Spring 框架的强大功能与 Kafka 分布式流平台结合,构建灵活且可扩展的事件驱动系统。通过添加 Spring Kafka 依赖并配置 Kafka 连接信息,可以轻松实现消息的生产和消费。文中详细展示了如何设置 `KafkaTemplate`、`ProducerFactory` 和 `ConsumerFactory`,并通过示例代码说明了生产者发送消息及消费者接收消息的具体实现。这一组合为构建高效可靠的分布式应用程序提供了有力支持。
109 0
|
3月前
|
Java Spring 供应链
Spring 框架事件发布与监听机制,如魔法风暴席卷软件世界,开启奇幻编程之旅!
【8月更文挑战第31天】《Spring框架中的事件发布与监听机制》介绍了Spring中如何利用事件发布与监听机制实现组件间的高效协作。这一机制像城市中的广播系统,事件发布者发送消息,监听器接收并响应。通过简单的示例代码,文章详细讲解了如何定义事件类、创建事件发布者与监听器,并确保组件间松散耦合,提升系统的可维护性和扩展性。掌握这一机制,如同拥有一把开启高效软件开发大门的钥匙。
46 0
|
4月前
|
安全 Java API
构建基于Spring Boot的REST API安全机制
构建基于Spring Boot的REST API安全机制
|
4月前
|
存储 设计模式 Java
Spring Boot中的事件溯源模式
Spring Boot中的事件溯源模式
|
5月前
|
Java 应用服务中间件 Spring
解析Spring Boot自动装配的原理与机制
解析Spring Boot自动装配的原理与机制
114 4
|
4月前
|
消息中间件 供应链 Java
实现基于Spring Cloud的事件驱动微服务
实现基于Spring Cloud的事件驱动微服务
|
4月前
|
Java 开发者 Spring
深入理解Spring Boot中的事件驱动架构
深入理解Spring Boot中的事件驱动架构