利用Spring Event实现SpringBoot单体架构的解耦与异步处理

219 阅读2分钟

在Spring Boot单体项目中,你可以使用Spring Event来处理应用程序中的事件。Spring Event是Spring框架中的一个重要组件,它允许你在应用程序中发布和监听事件,实现解耦和异步处理。

下面是在Spring Boot项目中如何使用Spring Event的简单示例: (可应用于大多数场景下的异步解耦开发)

通用配置

image.png

  1. 首先创建异步处理事件AsyncEvent,继承ApplicationEvent类:
import org.springframework.context.ApplicationEvent;
// 异步处理事件
public abstract class AsyncEvent extends ApplicationEvent {  
    public AsyncEvent(Object source) {  
        super(source);  
    }  
}
  1. 创建事件处理线程配置EventConfig类:
import java.util.concurrent.Executor;  
import java.util.concurrent.ThreadPoolExecutor;  
  
import javax.annotation.Nullable;  
  
import org.jetbrains.annotations.NotNull;  
import org.springframework.context.ApplicationEvent;  
import org.springframework.context.ApplicationListener;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.event.SimpleApplicationEventMulticaster;  
import org.springframework.context.support.AbstractApplicationContext;  
import org.springframework.core.ResolvableType;  
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
/**
* 事件处理线程配置
*/
@Configuration
public class EventConfig {
    @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME)  
    public SimpleApplicationEventMulticaster myEventMulticaster() {  
        MyApplicationEventMulticaster myApplicationEventMulticaster = new MyApplicationEventMulticaster();  
        myApplicationEventMulticaster.setTaskExecutor(taskExecutor());  
        return myApplicationEventMulticaster;  
    }
    
    @Bean  
    public ThreadPoolTaskExecutor taskExecutor() {  
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
        // 核心线程数  
        executor.setCorePoolSize(5);  
        // 最大线程数  
        executor.setMaxPoolSize(20);  
        // 队列容量  
        executor.setQueueCapacity(100);  
        // 线程活跃时间(秒)  
        executor.setKeepAliveSeconds(300);  
        // 线程名前缀  
        executor.setThreadNamePrefix("Async_event_executor-");  
        // 拒绝策略  
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());  
        // 关闭线程时是否等待  
        executor.setWaitForTasksToCompleteOnShutdown(true);  
        return executor;  
    }
    
    static class MyApplicationEventMulticaster extends SimpleApplicationEventMulticaster {  
        @Override  
        public void multicastEvent(@NotNull final ApplicationEvent event, @Nullable ResolvableType eventType) {  
            ResolvableType type = eventType != null ? eventType : resolveDefaultEventType(event);  
            Executor executor = this.getTaskExecutor();  
            for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {  
                // 配置了任务管理器 和 事件为异步处理事件,则调用任务处理器异步处理  
                if (executor != null && event instanceof AsyncEvent) {  
                    executor.execute(() -> this.invokeListener(listener, event));  
                } else {  
                    this.invokeListener(listener, event);  
                }  
            }  
        }  

        private ResolvableType resolveDefaultEventType(ApplicationEvent event) {  
            return ResolvableType.forInstance(event);  
        }  
    }
}

事件处理

  1. 创建异步事件(可根据业务自行定义)- 无参
public class TestEvent extends AsyncEvent {  
    public TestEvent(Object source) {  
        super(source);  
    }  
}

有参示例:

public class TestEvent extends AsyncEvent {  
    private String name;
    // ..... 可继续添加多个
    
    public TestEvent(Object source) {  
        super(source);  
    }  
    
    public TestEvent(Object source, String name, ......) {  
        super(source);  
        this.name = name;
        // ...... 
    }  
    
    public String getName() {  
        return name;  
    }
    
    // ...get
}
  1. 事件发布
@RequestMapping("/v1")  
@RestController  
public class EventController {  
    @Resource  
    private ApplicationEventPublisher publisher;  

    @GetMapping("/publish-event")  
    public String publishEvent(@RequestParam String name) { 
        // 无参事件发布
        publisher.publishEvent(new TestEvent(this));  
        // 需要带参就用这种方式
        // publisher.publishEvent(new TestEvent(this, name));  
        return "发布事件成功";  
    }  
}
  1. 事件监听处理,使用@EventListener注解搞定

service

/**
* @param: event 事件参数
*/
@EventListener  // 此注解也可直接写在serviceImpl
void listenerEvent(TestEvent event);

serviceImpl

@Override  
public void listenerEvent(TestEvent event) {  
    System.out.println("事件接收成功");  
    // 业务处理.....
    // 如果有参数可通过get获取
    // ......
    System.out.println("事件处理完成");  
}

注意:每个事件只需要定义一个,只需publishEvent发布一次,只要使用@EventListener注解的方法都会接收到对应的事件。(发布-订阅模式)