SpringBoot事件监听机制及发布订阅模式详解

业务需求:
用户注册成功之后,系统会给用户发放优惠券,发送邮件,发送短信等操作。

作为开发人员,很容易写出如下代码:

/**
 * 用户注册逻辑
 *
 * @author Lynch
 */
@GetMapping("/register")
public String register(String username) {
    // 注册
    userService.register(username);
    // 发送邮件
    emailService.sendEmail(username);
    // 发送短信
    smsService.sendEmail(username);
    // 发放优惠券
    couponService.addCoupon(username);
    return "注册成功!";
}

这样写会有什么问题?
1. 方法调用时,同步阻塞导致响应变慢,需要异步非阻塞的解决方案。
2. 注册接口此时做的事情:注册,发邮件,发短信,发优惠券,违反单一职责的原则。当然,如果后续没有拓展和修改的需求,这样子倒可以接受。
3. 如果后续注册的需求频繁变更,相应就需要频繁变更register方法,违反了开闭原则。

我们采用Spring事件监听机制解决以上存在的问题。

Spring事件监听机制概述
SpringBoot中事件监听机制则通过发布-订阅实现,主要包括以下三部分:
1. 事件 ApplicationEvent,继承JDK的EventObject,可自定义事件。
2. 事件发布者 ApplicationEventPublisher,负责事件发布
3. 事件监听者 ApplicationListener,继承JDK的EventListener,负责监听指定的事件

我们通过SpringBoot的方式,能够很容易实现事件监听,接下来我们实现下上面的案例:
一、定义注册事件——UserRegisterEvent

package cn.itcast.user.demo.event;

import org.springframework.context.ApplicationEvent;

/**
 * 定义注册事件
 *
 * @author Lynch
 */

public class UserRegisterEvent extends ApplicationEvent {
    private String username;
 
    public UserRegisterEvent(Object source) {
        super(source);
    }
 
    public UserRegisterEvent(Object source, String username) {
        super(source);
        this.username = username;
    }
 
    public String getUsername() {
        return username;
    }
}


二、注解方式 @EventListener定义监听器——CouponService

package cn.itcast.user.demo.event;

import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**
 * 监听用户注册事件,执行发放优惠券逻辑
 * 
 * @author Lynch
 *
 */
@Service
@Slf4j
public class CouponService {

    @EventListener
    public void addCoupon(UserRegisterEvent event) {
        log.info("给用户[{}]发放优惠券", event.getUsername());
    }
}


三、注解方式 @EventListener定义监听器——SmsService

package cn.itcast.user.demo.event;

import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**
 * 监听用户注册事件,异步执行发送短信逻辑
 * 
 * @author Lynch
 *
 */
@Service
@Slf4j
public class SmsService implements ApplicationListener<UserRegisterEvent> {
   
    @Override
    @Async("taskExecutor")
    public void onApplicationEvent(UserRegisterEvent event) {
        log.info("给用户[{}]发送短信", event.getUsername());
    }
}


四、实现ApplicationListener的方式定义监听器——EmailService

package cn.itcast.user.demo.event;

import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**
 * 监听用户注册事件,异步执行发送邮件逻辑
 * 
 * @author Lynch
 *
 */
@Service
@Slf4j
public class EmailService implements ApplicationListener<UserRegisterEvent> {
   
    @Override
    @Async("taskExecutor")
    public void onApplicationEvent(UserRegisterEvent event) {
        log.info("给用户[{}]发送邮件", event.getUsername());
    }
}


五、注册事件发布者——UserServiceImpl

package cn.itcast.user.demo.event;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

/**
 * 注册事件发布者
 * 
 * @author Lynch
 *
 */
@Service
@Slf4j
public class UserServiceImpl implements ApplicationEventPublisherAware {
    // 注入事件发布者
    private ApplicationEventPublisher applicationEventPublisher;
 
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
 
    /**
     * 发布事件
     */
    public void register(String username) {
        log.info("执行用户[{}]的注册逻辑", username);
        applicationEventPublisher.publishEvent(new UserRegisterEvent(this, username));
    }
}


六、单元测试——UserServiceImplTest

package cn.itcast.user.service;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import cn.itcast.user.BaseTest;
import cn.itcast.user.demo.event.UserServiceImpl;

public class UserServiceImplTest extends BaseTest {
    @Autowired
    private UserServiceImpl userServiceImpl;
    
    @Test
    public void register() {
        userServiceImpl.register("张三");
    }
}

运行结果如下:

11-17 14:39:49:520 INFO 20696 --- [ main] c.i.user.demo.event.UserServiceImpl : 执行用户[张三]的注册逻辑
11-17 14:39:49:522 INFO 20696 --- [ main] cn.itcast.user.demo.event.CouponService : 给用户[张三]发放优惠券
11-17 14:39:49:533 INFO 20696 --- [viceExecutor -1] cn.itcast.user.demo.event.EmailService : 给用户[张三]发送邮件
11-17 14:39:49:534 INFO 20696 --- [viceExecutor -2] cn.itcast.user.demo.event.SmsService : 给用户[张三]发送短信

 

posted on 2022-11-17 15:00  Ruthless  阅读(1936)  评论(0编辑  收藏  举报