首页 > 其他分享 >SpringBoot事件监听机制及发布订阅模式详解

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

时间:2022-11-17 15:15:59浏览次数:49  
标签:username SpringBoot 监听 springframework public 详解 org import event

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

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

/**
 * 用户注册逻辑
 *
 * @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 : 给用户[张三]发送短信

 

标签:username,SpringBoot,监听,springframework,public,详解,org,import,event
From: https://www.cnblogs.com/linjiqin/p/16899532.html

相关文章

  • Vue 中 watch 监听器与 computed 计算属性的使用
    一、watch:监视单个属性,可做简单监视和深度监视。根据数据的具体结构,决定是否采用深度监视。配置deep:true可以监测对象内部值的改变,做深度监视时使用。1、简单监视:监视单......
  • [SpringBoot-Dubbo] 报错:NoClassDefFoundError: org/apache/curator/framework/recipe
    NoClassDefFoundError:org/apache/curator/framework/recipes/cache/NodeCacheListener缺少curator依赖<dependency><groupId>org.apache.curator</groupId><ar......
  • SpringBoot报错 java.lang.IllegalArgumentException: class org.springframework.boo
    多版本SpringBoot版本冲突java.lang.IllegalArgumentException:classorg.springframework.boot.cloud.CloudFoundryVcapEnvironment是版本问题classorg.springframe......
  • Redis中主从复制的原理详解
    主从复制的方式命令slaveof。优点:无需重启。缺点:不便于管理 //命令行使用slaveofipport//使用命令后自身数据会被清空,但取消slave只是停止复制,并不清空修改配置。优......
  • 学习springboot2的第7天(2021-12-06)43-视图解析-Thymeleaf初体验
    学习springboot2的第7天(2021-12-06)43-视图解析-Thymeleaf初体验视图解析:指的就是springboot在处理完请求之后想要跳转到某个页面的过程。springboot默认不支持JSP,需要引入第......
  • Python删除文件多种方法详解!
    在开发过程中,创建文件之后当我们不需要这个文件或者创建错了就需要删除该文件,那么Python中删除文件的方法有几种?使用Python删除文件有多种方法,本文为大家介绍几种常用......
  • Android Handler详解
    本期主要内容1:Handler是什么?2:为什么要使用Handler?3:Handler/Looper/MessageQueue/Message究竟是做什么的?4:Handler如何去实现发送和处理消息1、Handler是......
  • Linux 用户及用户组相关文件、命令详解
    Linux用户及用户组相关文件、命令详解1.用户、用户组概念及其文件结构详解​ Linux用户只有两个等级:root及非root。Linux中还有一部分用户,如:apache、mysql、nobody、f......
  • redis info 详解
    info系统状态说明info命令的使用方法有以下三种:info:部分Redis系统状态统计信息。infoall:全部Redis系统状态统计信息。infosection:某一块的系统状态统计......
  • Java 中foreach()循环,增强for循环详解
    ​foreach循环简称增加for循环用于遍历数组,集合@Testpublicvoidtest2(){Collectioncoll=newArrayList();coll.add(123);coll.add("程......