Spring-Event入门实践及执行原理

一、入门案例

1. 添加依赖
首先,在 pom.xml 文件中添加 Spring Boot 和 Spring Event 的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2. 定义自定义事件
创建一个自定义事件类 CustomEvent,继承自 ApplicationEvent:

package com.example.demo.event;

import org.springframework.context.ApplicationEvent;

public class CustomEvent extends ApplicationEvent {
    private String message;

    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

3. 创建事件监听器
创建一个事件监听器类 CustomEventListener,实现 ApplicationListener 接口:

package com.example.demo.listener;

import com.example.demo.event.CustomEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("Received custom event - " + event.getMessage());
    }
}

4. 发布事件
在 DemoApplication 类中,注入 ApplicationEventPublisher 并发布自定义事件:

package com.example.demo;

import com.example.demo.event.CustomEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationEventPublisher;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private ApplicationEventPublisher publisher;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        CustomEvent event = new CustomEvent(this, "Hello, Spring Event!");
        publisher.publishEvent(event);
    }
}

5. 运行应用
运行 DemoApplication 类,启动 Spring Boot 应用程序。你应该会在控制台看到以下输出:

收到:com.sun.springevent.SpringEventApplication$$SpringCGLIB$$0@6e3ecf5c消息;时间:1731466981066;消息:Hello, Spring Event!

二、Spring-Event执行原理

Spring Event 机制是 Spring 框架中的一个事件驱动模型,用于在应用程序的不同组件之间进行解耦和通信。下面是 Spring Event 的执行原理的详细解释:

1. 事件 (Event)
  定义:事件是应用程序中发生的一个特定动作或状态变化。
  实现:在 Spring 中,事件通常是由一个继承自 ApplicationEvent 的类表示的。例如,我们之前定义的 CustomEvent 就是一个自定义事件。
2. 事件发布者 (Event Publisher)
  定义:事件发布者是负责创建并发布事件的组件。
  实现:在 Spring 中,可以通过 ApplicationEventPublisher 接口来发布事件。通常,这个接口会通过依赖注入的方式注入到需要发布事件的类中。
3. 事件监听器 (Event Listener)
  定义:事件监听器是负责处理事件的组件。
  实现:在 Spring 中,可以通过实现 ApplicationListener 接口或者使用 @EventListener 注解来定义事件监听器。
4. 事件传播过程
  1、事件创建:
    事件发布者创建一个 ApplicationEvent 的实例,并传递必要的参数。
  2、事件发布:
    事件发布者调用 ApplicationEventPublisher 的 publishEvent 方法,将事件对象传递给 Spring 容器。
  3、事件分发:
    Spring 容器接收到事件后,会查找所有注册了该事件类型的监听器。
    Spring 容器会调用每个监听器的 onApplicationEvent 方法(如果使用 ApplicationListener 接口)或带有 @EventListener 注解的方法。
  4、事件处理:
    监听器接收到事件后,根据事件的内容执行相应的业务逻辑。
5. 异步事件处理
  默认行为:Spring 事件默认是同步处理的,即事件发布者会等待所有监听器处理完事件后才会继续执行后续代码。
  异步处理:可以通过配置 ApplicationEventMulticaster 来实现异步事件处理。通常,可以在 application.properties 或 application.yml 中配置 TaskExecutor 来实现异步处理。
6. 示例代码解释
  CustomEvent:定义了一个自定义事件类,继承自 ApplicationEvent,并添加了一个 message 属性。
  CustomEventListener:定义了一个事件监听器类,实现了 ApplicationListener<CustomEvent> 接口,并重写了 onApplicationEvent 方法来处理事件。
  DemoApplication:主类,实现了 CommandLineRunner 接口,在 run 方法中创建并发布了一个 CustomEvent 事件。


总结
  Spring Event 机制通过事件发布者、事件监听器和事件本身,实现了组件之间的松耦合和灵活的事件驱动架构。通过这种方式,可以更容易地管理和扩展应用程序的功能。

 

三、深入地探讨publisher.publishEvent(event) 背后的具体执行流程和机制。

1. 事件发布方法 publishEvent

当你调用 ApplicationEventPublisher 的 publishEvent 方法时,Spring 容器会执行一系列操作来处理这个事件。以下是详细的步骤:

1.1 调用 publishEvent 方法

publisher.publishEvent(event);

1.2 AbstractApplicationContext 中的 publishEvent 方法

ApplicationEventPublisher 接口的实现类通常是 AbstractApplicationContext,它是 Spring 容器的核心类之一。

AbstractApplicationContext 中的 publishEvent 方法会调用 doPublishEvent 方法来处理事件。

public void publishEvent(ApplicationEvent event) {
    assertContextActive();
    getApplicationEventMulticaster().multicastEvent(event);
}

2. 事件多播器 ApplicationEventMulticaster

ApplicationEventMulticaster 是负责将事件广播给所有注册的监听器的组件。默认情况下,Spring 使用 SimpleApplicationEventMulticaster 实现。

2.1 multicastEvent 方法

SimpleApplicationEventMulticaster 的 multicastEvent 方法会遍历所有注册的监听器,并调用它们的 onApplicationEvent 方法。

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        } else {
            invokeListener(listener, event);
        }
    }
}

3. 事件监听器调用

3.1 invokeListener 方法

invokeListener 方法会调用具体的监听器方法来处理事件。

private void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler == null) {
        doInvokeListener(listener, event);
    } else {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
}

private void doInvokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    try {
        // 调用监听器的 onApplicationEvent 方法
        listener.onApplicationEvent(event);
    }
    catch (ClassCastException ex) {
        String msg = ex.getMessage();
        if (msg == null || matchesClassName(ex, event.getClass(), msg) ||
                matchesClassName(ex, ResolvableType.forInstance(event).getRawClass(), msg)) {
            String className = listener.getClass().getName();
            if (logger.isWarnEnabled()) {
                logger.warn("Non-matching event type for listener [" + className + "]");
            }
        }
        else {
            throw ex;
        }
    }
}

4. 异步事件处理

4.1 配置 TaskExecutor

如果希望事件处理是异步的,可以在 application.properties 或 application.yml 中配置 TaskExecutor。例如:

spring:
  task:
    execution:
      pool:
        core-size: 5
        max-size: 10
        queue-capacity: 100

4.2 自定义 ApplicationEventMulticaster

也可以通过自定义 ApplicationEventMulticaster 来实现更复杂的事件处理逻辑。例如:

@Configuration
public class EventConfig {

    @Bean
    public ApplicationEventMulticaster applicationEventMulticaster() {
        SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster();
        eventMulticaster.setTaskExecutor(new SimpleAsyncTaskExecutor());
        return eventMulticaster;
    }
}

5. 事件监听器的注册

5.1 通过 @Component 注解

可以使用 @Component 注解将监听器类注册为 Spring 管理的 Bean。

@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
    @Override
    public void onApplicationEvent(CustomEvent event) {
        System.out.println("Received custom event - " + event.getMessage());
    }
}

5.2 通过 @EventListener 注解

也可以使用 @EventListener 注解来定义事件监听器方法。

@Component
public class CustomEventListener {

    @EventListener
    public void handleCustomEvent(CustomEvent event) {
        System.out.println("Received custom event - " + event.getMessage());
    }
}

总结
  通过上述步骤,我们可以看到 publisher.publishEvent(event) 背后的详细执行流程。Spring 容器通过 ApplicationEventMulticaster 将事件广播给所有注册的监听器,并调用它们的 onApplicationEvent 方法来处理事件。此外,Spring 还提供了异步事件处理和自定义事件多播器的能力,以满足更复杂的应用需求。

 

posted @ 2024-11-13 11:49  佛祖让我来巡山  阅读(206)  评论(0编辑  收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网