Spring 事件机制

背景

大家在做项目的时候,往往会遇到一些不是主流程的功能,但是需要在主流程中触发的功能,比如在保险领域的签单流程中需要给用户发送短信或者邮件的功能。

分析

我们都知道这些非主流程中功能,最好不要让主线程去执行,这个时候我们能想到的就是异步线程去执行,我们可以单独搞个线程池,然后异步处理这些任务。
但是总是感觉不太优雅。这时我们可以结合Spring的事件机制加上异步线程去实现这些功能。

实现

我们假定现在你有一个后台管理系统,涉及到登陆和注册两个场景,在注册和登录成功后给用户发送短信邮件提醒或者其他的功能。

创建工程

我们为了测试方便就直接创建一个简单的Spring Boot的工程就可以了。创建的时候引入如下依赖:

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

  <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
  </dependency>

创建事件接口

为了定义统一事件行为,我们定义一个事件接口,代码如下:

public interface Event {
    /**
     * 发送短信
     */
    void sendMsg();

    /**
     * 发送邮件
     */
    void sendMail();

    /**
     * 其他行为
     */
    void other();
}

创建登录事件

创建一个登陆事件类,并且实现事件接口。代码如下:

@Data
@Slf4j
public class LoginEvent implements Event {
    /**
     * 登录的姓名
     */
    private String  name;

    public LoginEvent(String name) {
        this.name = name;
    }

    @Override
    public void sendMsg() {
      log.info("登录短信内容为:你好:{},欢迎登录该系统",name);
    }

    @Override
    public void sendMail() {
        log.info("登录邮件内容为:你好:{},欢迎登录该系统",name);
    }

    @Override
    public void other() {
        log.info("登录其他内容为:你好:{},欢迎登录该系统",name);
    }
}

说明:为什么我们要创建一个接口呢?其实是为了使用策略模式,最大程度的复用事件监听主要代码。

创建注册事件

创建一个登陆事件类,并且实现事件接口。代码如下:

@Data
@Slf4j
public class RegisterEvent implements Event  {
    /**
     * 注册人的姓名
     */
    private String  name;

    public RegisterEvent(String name) {
        this.name = name;
    }

    @Override
    public void sendMsg() {
        log.info("注册短信内容为:你好:{},欢迎注册该系统",name);
    }

    @Override
    public void sendMail() {
        log.info("注册邮件内容为:你好:{},欢迎注册该系统",name);
    }

    @Override
    public void other() {
        log.info("注册其他内容为:你好:{},欢迎注册该系统",name);
    }
}

创建事件监听

大家注意,事件监听代码的入参是事件监听的接口,这就是为什么要创建一个接口的原因。

注解解释:
@EventListener-代表是一个监听器
@Async-这个方法需要异步执行

@Component
@Slf4j
public class EventsListener {
    /**
     * 事件监听
     * @param event
     */
    @Async
    @EventListener
    public void handelListener(Event event){
        event.sendMsg();
        event.sendMail();
        event.other();
    }
}

测试

我们创建测试类,并且用postman进行测试

创建测试类

我们创建一个控制器来测试登陆和注册的功能。代码如下:

@RestController
public class EventController {

    @Resource
    LoginService loginService;
    @Resource
    private ApplicationEventPublisher applicationContext;

    @GetMapping("/login")
    private String testLoginEvent(){
        //登陆的逻辑
        loginService.login("张三");
        //登陆完成后发布登陆后的事件
        applicationContext.publishEvent(new LoginEvent("张三"));
        return "success";
    }

    @GetMapping("/register")
    private String testRegisterEvent(){
        applicationContext.publishEvent(new RegisterEvent("张三"));
        return "success";
    }
}

测试

我们Sping Boot项目,并且进行测试,来看一下效果。

使用postman请求我们的login方法,我们观察一下日志。请求地址localhost:8111/login,日志如下:

2023-07-16 17:25:16.774  INFO 7070 --- [nio-8111-exec-1] o.t.s.e.service.impl.LoginServiceImpl    : 欢迎:张三,登陆系统。
2023-07-16 17:25:16.795  INFO 7070 --- [         task-1] o.t.s.eventlistener.event.LoginEvent     : 登录短信内容为:你好:张三,欢迎登录该系统
2023-07-16 17:25:16.795  INFO 7070 --- [         task-1] o.t.s.eventlistener.event.LoginEvent     : 登录邮件内容为:你好:张三,欢迎登录该系统
2023-07-16 17:25:16.795  INFO 7070 --- [         task-1] o.t.s.eventlistener.event.LoginEvent     : 登录其他内容为:你好:张三,欢迎登录该系统

可以看到,我们的请求的线程是[nio-8111-exec-1],事件监听的执行是异步线程[task-1],这样就实现了我们文章开头所说的功能。

说明

大家在使用Spring Boot的过程中使用到@Async注解时记得开启该注解的使用。代码如下:

@SpringBootApplication
@EnableAsync
public class SpringbootApplication {

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

}

小结

本篇文章,我们简单的在实现层面整理了使用Spring的事件监听机制实现异步功能,后续有机会带着大家分析一下这部分源码,详细代码,大家可以直接进行下载使用源码地址
希望对大家有所帮助。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值