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

发布时间:2024年01月22日

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

介绍

什么是观察者模式

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

代码实现

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

图片来自菜鸟教程

使用场景

观察者模式一般就是解耦用的, 比如你需要调用发邮件通知啊,向消息队列里推送消息啊. 这些与核心业务关系不大, 又不想破坏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"包. 把所有的事件监听规整起来.这样代码相对整洁一些~

参考资料

https://juejin.cn/post/7323793129710551080

文章来源:https://blog.csdn.net/weixin_42577159/article/details/135702719
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。