[人话版]spring事件监听机制 和观察者模式

声明: 此文章仅限于记录学习之用 , 受限于自身水平和理解能力 , 因此结论可能是不正确的. 如果您需要学习,建议参考其他文章

介绍

什么是观察者模式

打个比方 你骑着电瓶车上班, 走到路口红灯亮了, 大家都抬着头看那圆圆的猴屁股啥时候变绿. 只要变绿,必须电门拧到底,率先冲出线,才有可能不迟到~~
上述例子中观者者是"各位骑士" ,被观察者 “红绿灯”. . 当被观察者发生变化时, 观察者做出相应动作. 这就是观察者模式.
超市抢鸡蛋,图片来自百度搜索

代码实现

有了上述定义, 代码实现就比较简单了. 定义观察者 和被观察者. 被观察者变化时, 遍历循环被观察者就完事了~

图片来自菜鸟教程

使用场景

观察者模式一般就是解耦用的, 比如你需要调用发邮件通知啊,向消息队列里推送消息啊. 这些与核心业务关系不大, 又不想破坏service的纯洁性(单一职责). 可以让代码更规范些.
试想一下. 你在orderService中 又引入了 EmailService是不是多多少少有点不合适…

springBoot简化事件监听

大家了解完观察者模式了, 一般还是很少用, 因为用起来不方便… 我学习设计模式也有这个烦恼, 就是例子与实际差别太大了. 想使用又很麻烦… 经常开发的人都知道,只要遇到开发不科学的问题, spring就一定会有解决方案. . .

springboot 事件监听使用示例

下面以用户信用卡扣款成功后, 发送email和短信通知为例.

  1. 定义实体类. (短信通知和邮件通知)
package com.isimple.portal.model;

/**
 * @author Administrator
 * @version 1.0
 * @description: 邮箱通知
 * @date 2024/1/17 16:12
 */
public class Email {
    /**
     * 邮箱地址
     */
    private  String address;

    public Email(String address) {
        this.address = address;
    }

    public String getAddress() {
        return address;
    }
}


package com.isimple.portal.model;

/**
 * @author Administrator
 * @version 1.0
 * @description:  短信通知
 * @date 2024/1/17 16:12
 */
public class SMS {
    private  String phoneNumber;

    public SMS(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }
}

  1. 定义event, 通过泛型传入实体类
package com.isimple.portal.model;

import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;

/**
 * @author Administrator
 * @version 1.0
 * @description: 消息通知
 * @date 2024/1/17 16:13
 */

/**
 * 注意: implements ResolvableTypeProvider 是为了解决泛型擦除问题.
 */
public class NoticeEvent<T> implements ResolvableTypeProvider {
    
    private T data;
    /**
     * 通知内容
     */
    private String message;

    public NoticeEvent(T data, String message) {
        this.data = data;
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    /**
     * 重写此方法解决泛型擦除问题
     * @return
     */
    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getData()));

    }
}

  1. 定义事件监听(eventListenner)
package com.isimple.portal.model;

import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;

/**
 * @author Administrator
 * @version 1.0
 * @description: 消息通知
 * @date 2024/1/17 16:13
 */

/**
 * 注意: implements ResolvableTypeProvider 是为了解决泛型擦除问题.
 */
public class NoticeEvent<T> implements ResolvableTypeProvider {

    private T data;
    /**
     * 通知内容
     */
    private String message;

    public NoticeEvent(T data, String message) {
        this.data = data;
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMessage() {
        return message;
    }

    /**
     * 重写此方法解决泛型擦除问题
     * @return
     */
    @Override
    public ResolvableType getResolvableType() {
        return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forInstance(getData()));

    }
}


  1. 业务service调用事件监听
package com.isimple.portal.service.impl;

import com.isimple.portal.model.Email;
import com.isimple.portal.model.NoticeEvent;
import com.isimple.portal.model.SMS;
import com.isimple.portal.service.EventDemoService;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author Administrator
 * @version 1.0
 * @description:
 * @date 2024/1/22 11:08
 */
@Service
public class EventDemoServiceImpl implements EventDemoService {

    @Resource
    private ApplicationContext applicationContext;

    @Override
    public String notice(String code) {
        String message = "[工业银行]尊敬的吴老二,你好,本次消费1000.00元,余额0元";
        if ("sms".equals(code)) {
            applicationContext.publishEvent(new NoticeEvent<SMS>(new SMS("13800138000"), message));
        }
        if ("email".equals(code)) {
            applicationContext.publishEvent(new NoticeEvent<Email>(new Email("10001@qq.com"), message));
        }
        return "success";
    }
}

这样做完, 事件监听就已经和业务代码解耦了, 也可以进一步整理,比如 建立"event"包. 把所有的事件监听规整起来.这样代码相对整洁一些~

后记20240205

上述代码只能算是观察者模式的变种. 真正观察者模式解决的主要是问题就是解耦.便于后期新增或删除通知种类. 比如后期又添加了新的通知方式. 比较正规的做法是通过动态添加订阅者来完成, 管理员通过后台✔来启用禁用.

参考资料

https://juejin.cn/post/7323793129710551080

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值