Spring Event如何优雅实现系统业务解耦

Spring Event如何优雅实现系统业务解耦

一、介绍

Spring事件(Spring Event)是Spring框架的一项功能,它允许不同组件之间通过发布-订阅机制进行解耦的通信。在Spring中,事件是表示应用程序中特定事件的对象,例如用户注册、订单创建、数据更新等。当这些事件发生时,可以通知其他组件来执行相应的操作。

具体来说,Spring事件机制包含以下几个主要的部分:

1、事件(Event):

事件是一个普通的POJO类,用于封装与应用程序状态变化相关的信息。通常情况下,事件类继承自ApplicationEvent抽象类,Spring中提供了一些内置的事件,也可以自定义事件。
2、事件发布者(ApplicationEventPublisher):

事件发布者是一个接口,用于发布事件。在Spring中,ApplicationContext就是一个事件发布者,可以通过ApplicationContext的publishEvent()方法来发布事件。
3、事件监听器(ApplicationListener):

事件监听器是一个接口,用于监听事件并在事件发生时执行相应的逻辑。在Spring中,我们可以通过实现ApplicationListener接口或使用@EventListener注解来定义事件监听器。
4、 事件监听器注册:

事件监听器需要注册到事件发布者(ApplicationContext)中,以便在事件发生时被正确调用。在Spring中,通常通过XML配置、注解或者编程方式将事件监听器注册到ApplicationContext中。

设计模式:订阅发布模式

Spring Event是一种基于观察者模式(Observer Pattern)的实现。观察者模式(Observer Design

Pattern)也被称为发布订阅模式。其定义是:在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。

二、代码示例

Spring Boot并不会自动默认维护一个线程池来处理event事件,也就是说他的订阅发布是同步。要想异步处理事件使用 @Async标记即可,注意前提条件是:使用 @EnableAsync 开启 Spring 异步

2.1 定义实体类
java 复制代码
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    private Long id;
    private String userNo;
    private String nickname;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer isDelete;

}
2.2 自定义一个注册事件
java 复制代码
@Getter
public class RegisterEvent extends ApplicationEvent {

    private Employee employee;

    public RegisterEvent(Object source, Employee employee) {
        super(source);
        this.employee = employee;
    }
}

注意这里的类名,对于多个发布事件,就是靠订阅不同的注册事件类名来区分

2.3 定义事件监听器

方法一 实现ApplicationListener接口
方法二 使用@EventListener注解。

java 复制代码
@Slf4j
@Component // 把监听器注册到spring容器中,(这里的RegisterEvent就是指哪个发布事件)
@Async("asyncExecutor")
public class RegisterMsgNoticeListener implements ApplicationListener<RegisterEvent> {
    @Override
    public void onApplicationEvent(RegisterEvent event) {
        log.info("=========>>>站内信通知了");
    }
}
java 复制代码
@Slf4j
@Component
public class RegisterPushDataListener{
	//注意使用纾解的方式,@Async需加在方法上
    @EventListener
    @Async("asyncExecutor")
    public void onApplicationEvent(RegisterEvent event) {
        log.info("======>>>推送用户信息到大数据系统了,user={}", event.getUser());
    }
}
2.4 发布事件

实现类

java 复制代码
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Resource
    private ApplicationContext applicationContext;


    @Override
    public void registerUser(User user) {
        log.info("=====>>>user注册成功了");
        applicationContext.publishEvent(new RegisterEvent(this, user));
    }
}

注意:这里的ApplicationContext 是import org.springframework.context.ApplicationContext;

接口

java 复制代码
public interface EmployeeService {
    void register(Employee employee);
}

控制层

java 复制代码
@PostMapping("/register")
    public void register() {
        Employee user = Employee.builder().userNo("1111").birthday(new Date()).gender(0)
                .phone("120").email("123@163.com").nickname("雪飘人间").build();
        employeeService.register(user);
    }
2.5 主启动类加异步线程注解
java 复制代码
@EnableAsync
@SpringBootApplication
public class SimpleSadApplication {

    public static void main(String[] args) {
        System.out.println("系统开始启动............");
        long l1 = System.currentTimeMillis();
        SpringApplication.run(SimpleSadApplication.class, args);
        long l2 = System.currentTimeMillis();
        System.out.println("系统启动完毕,用时:"+(l2-l1)+"毫秒!");
    }
}
2.6 自定义线程池
java 复制代码
@Configuration
public class InitThreadPool {
    @Bean(name = "asyncExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(200);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("asyncExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

调用接口:可以看到,输出结果,订阅已发布也已经解耦了,但是多个订阅者的顺序是随机的

三、spring Event优缺点

优点:

简单易用: Spring Event是Spring框架提供的一个内置的事件发布-订阅机制,使用起来非常简单,无需引入额外的依赖。

无中间件依赖: Spring Event不依赖于任何消息中间件,适用于小型项目或者简单的消息通信场景。

模块解耦: Spring Event可以帮助实现模块之间的解耦,提高系统的灵活性和可维护性。

缺点:

单点问题: Spring Event是在单个应用内部的事件通知机制,如果应用崩溃或者重启,事件将会丢失。

不支持分布式: Spring Event只能在单个应用内部传递消息,不支持分布式环境下的消息传递。

性能问题: Spring Event在大规模消息通信场景下可能会存在性能问题,因为它是同步执行的,消息发布者需要等待所有订阅者处理完消息后才能继续执行

相关推荐
这孩子叫逆11 分钟前
Spring Boot项目的创建与使用
java·spring boot·后端
星星法术嗲人15 分钟前
【Java】—— 集合框架:Collections工具类的使用
java·开发语言
一丝晨光33 分钟前
C++、Ruby和JavaScript
java·开发语言·javascript·c++·python·c·ruby
天上掉下来个程小白36 分钟前
Stream流的中间方法
java·开发语言·windows
xujinwei_gingko1 小时前
JAVA基础面试题汇总(持续更新)
java·开发语言
liuyang-neu1 小时前
力扣 简单 110.平衡二叉树
java·算法·leetcode·深度优先
一丝晨光1 小时前
Java、PHP、ASP、JSP、Kotlin、.NET、Go
java·kotlin·go·php·.net·jsp·asp
罗曼蒂克在消亡1 小时前
2.3MyBatis——插件机制
java·mybatis·源码学习
_GR1 小时前
每日OJ题_牛客_牛牛冲钻五_模拟_C++_Java
java·数据结构·c++·算法·动态规划
coderWangbuer1 小时前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql