首页 > 其他分享 >Google Guava 发布订阅模式/生产消费者模式 使用详情

Google Guava 发布订阅模式/生产消费者模式 使用详情

时间:2024-11-03 15:19:17浏览次数:4  
标签:订阅 Google 模式 public 发送 事件 监听器 Guava event

目录

Guava 介绍

应用场景举例

1. 引入 Maven 依赖

 2. 自定义 Event 事件类

3. 定义 EventListener 事件订阅者

4. 定义 EventBus 事件总线

5. 定义 Controller 进行测试


Guava 介绍

        Guava 是一组来自 Google 的核心 Java 库,里面包括新的集合 类型(例如 Multimap 和 MultiSet),不可变集合、图形库、 以及用于并发、I/O、哈希、基元、字符串,发布/订阅模式等等。接下来主要讲解 发布订阅模式。

Guava 发布订阅主要包含以下主要核心部分:

  • Event 事件
  • Publisher 事件发布者
  • EventListener 事件订阅者
  • EventBus 事件总线

工作流程

        Publisher 事件发布者  通过 EventBus 事件总线 发布事件,然后 EventBus 事件总线 把事件传给 Subscriber 事件订阅者 消费。

工作原理图

应用场景举例

        当用户注册App后,可能会产生很多行为,比如需要发短信提醒用户,注册成功,获取100积分,又或者需要给注册成功的用户送优惠卷。如果按我们平时的写法,则需要在用户注册成功后,返回请求前,需要引入发短信和发优惠卷的逻辑,不仅使冗余在注册代码中,造成耦合度太高。职责不分离。

        这时就可以引入Guava 的发布订阅模式。让发送短信的监听器 和 发优惠卷的监听器 同时监听同一个事件即可。

1. 引入 Maven 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <groupId>com.xinxin</groupId>
    <artifactId>cyh</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>
    </dependencies>
</project>

 2. 自定义 Event 事件类

        Event 类是我们生产者和消费者 消息传播的载体,也就是发送的内容,通常我们以 Event 为后缀来命名事件类。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @description: 用户注册事件
 * @author: cyh
 * @create: 2024-11-02 17:07
 **/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserRegisterEvent {
    private Long userId;

    private Date registerTime;
}

3. 定义 EventListener 事件订阅者

        事件订阅者即事件的监听者,接受事件消费的一端。监听者会一直监听他们所关注的事件。

事件订阅者的定义,需要在方法上添加@Subscribe注解声明自己为事件订阅者,然后方法参数是他们监控的 Event 事件。

    一般@Subscribe可以配合@AllowConcurrentEvents注解一起使用,这个注解是用来标识当前订阅者是线程安全的,可以减少同步开销。

3.1 定义 发送短信 事件订阅者

/**
 * @description: 短信事件监听器
 * @author: cyh
 * @create: 2024-11-02 17:10
 **/
@Slf4j
@Component
public class SmsEventListener {


        @Subscribe
        @AllowConcurrentEvents
        public void recordRegisterLog(UserRegisterEvent event) {
            Long userId = event.getUserId();
            Date registerTime = event.getRegisterTime();
            log.info("短信监听器 监听到用户注册行为,用户 {} 在 {} 注册成功,事件内容为:{}", userId, registerTime, JSON.toJSONString(event));
            //发送短信通知
            log.info("发送短信通知");
        }
        
}

3.2 定义 发送优惠卷 事件订阅者

/**
 * @description: 优惠卷事件监听器
 * @author: cyh
 * @create: 2024-11-02 17:10
 **/
@Slf4j
@Component
public class CouponEventListener {

        @Subscribe
        @AllowConcurrentEvents
        public void recordRegisterLog(UserRegisterEvent event) {
            Long userId = event.getUserId();
            Date registerTime = event.getRegisterTime();
            log.info("优惠卷监听器 监听到用户注册行为,用户 {} 在 {} 注册成功,事件内容为:{}", userId, registerTime, JSON.toJSONString(event));
            //发送优惠卷
            log.info("发送优惠卷");
        }
}

4. 定义 EventBus 事件总线

        EventBus 事件总线的作用是,将 Event 事件 转发给 EventListener 事件订阅者。所以 首先我们就要把 事件订阅者注册给总线,它才知道有哪些订阅者需要转发。 然后将不同的 Event 事件 转发给订阅了该事件的订阅者。

事件总线有两个作用:

  •   发布消息
  •   转发消息给订阅者        

4.1 EventBus 事件总线,代码定义

/**
 * @description:  事件总线
 * @author: cyh
 * @create: 2024-11-02 17:16
 **/
@Slf4j
@Component
public class EventBusCenter {

    private static EventBus eventBus;
    private static AsyncEventBus asyncEventBus;
    private static Executor executor = new ThreadPoolExecutor(12, 12, 60,
            TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());

    /**
     * 异步事件单例模式
     * @return
     */
    private static synchronized AsyncEventBus getAsyncEventBus() {
        if(asyncEventBus == null){
            asyncEventBus = new AsyncEventBus(executor);
        }
        return asyncEventBus;
    }

    /**
     * 同步事件单例模式
     * @return
     */
    private static synchronized EventBus getEventBus() {
        if(eventBus == null) {
            eventBus = new EventBus();
        }
        return eventBus;
    }

    public static void register(Object object) {
        getEventBus().register(object);
        getAsyncEventBus().register(object);
    }

    public static void unregister(Object object) {
        getEventBus().unregister(object);
        getAsyncEventBus().unregister(object);
    }


    /**
     * 同步发送事件
     * @param event
     */
    public static void post(Object event) {
        log.info("同步发送事件内容:{}", JSON.toJSONString(event));
        eventBus.post(event);
    }



    /**
     * 异步发送事件
     * @param event
     */
    public static void asyncPost(Object event) {
        log.info("异步发送事件内容:{}", JSON.toJSONString(event));
        asyncEventBus.post(event);
    }
}

 4.2 将 EventListener 事件订阅者注册到总线中

@Order(1)
@Slf4j
@Component
@Configuration
public class RegisterListenerToBus implements ApplicationListener<ApplicationReadyEvent> {
 
    @Resource
    private SmsEventListener smsEventListener;
    @Resource
    private CouponEventListener couponEventListener;
    

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        log.info("ApplicationReadyEvent init restTemplate.");
        try {
            //监听器注册
            EventBusCenter.register(smsEventListener);
            EventBusCenter.register(couponEventListener);
        } catch (Exception e) {
            log.error("初始化配置失败!", e);
        }
        log.info("ApplicationReadyEvent init restTemplates finished.");
    }
 
}

5. 定义 Controller 进行测试

/**
 * @description:
 * @author: cyh
 * @create: 2024-11-02 17:28
 **/
@RestController
public class RegisterController {

    @GetMapping("/register")
    public String register(Long userId){
        UserRegisterEvent event = new UserRegisterEvent(userId, new Date());
        //同步发送
        EventBusCenter.post(event);
//        //异步发送
//        EventBusCenter.asyncPost(event);
        return "ok";
    }
}

测试结果

同步发送事件内容:{"registerTime":1730557363231,"userId":1594}
短信监听器 监听到用户注册行为,用户 1594 在 Sat Nov 02 22:22:43 CST 2024 注册成功,事件内容为:{"registerTime":1730557363231,"userId":1594}
发送短信通知
优惠卷监听器 监听到用户注册行为,用户 1594 在 Sat Nov 02 22:22:43 CST 2024 注册成功,事件内容为:{"registerTime":1730557363231,"userId":1594}
发送优惠卷

标签:订阅,Google,模式,public,发送,事件,监听器,Guava,event
From: https://blog.csdn.net/weixin_46203834/article/details/143454015

相关文章

  • Google远程过程调用-GRPC
    前言HTTP/2是HTTP协议的第二个主要版本,它在HTTP/1.x的基础上引入了许多改进,以提高网络性能和效率。以下是HTTP/2与HTTP/1.x之间的一些主要区别:•二进制协议:•HTTP/2:采用二进制格式,而不是HTTP/1.x的文本格式。这使得解析更快、更高效。•HTTP/1.x:基于文本的协议,......
  • 【设计模式系列】原型模式(十一)
    一、什么是原型模式原型模式(PrototypePattern)是一种创建型设计模式,它使得一个对象可以复制自身,从而创建一个与自己属性一致的新对象,而无需知晓对象创建的细节。这种模式允许动态地增加对象的数量,并通过复制现有的对象来提高效率,特别是当直接创建对象的代价较大时(例如,涉及复杂......
  • App第一次上Google Play需要准备什么?
        这几年随着国内企业出海的数量越来越多,在googleplay上架的应用也是急速的增长,同时googleplay政策也越来越严格。第一次上架app需要提前做好哪些准备呢?这里我简单的梳理了一下,主要包含以下几个方面。1、注册开发者账号googleplay开发者账号目前分为个人和企业......
  • es6 语法学习 - 解释器模式
    es6语法学习-解释器模式一、基本概念解释器设计模式(InterpreterPattern)是一种行为型设计模式,它用于将一种特定的语言或表达式转换为对象,并通过解释器来解释和执行这些对象。二、优点扩展性好:由于语法由很多类表示,因此容易改变及扩展语言。灵活性高:可以根据不同的规......
  • 异步编程的利之Future模式深入解析(In Depth Analysis of Future Patterns)
     ......
  • Google语法(详见b站泷羽sec)
    "inurl:admin":查找包含“admin”的网页URL,可能找到管理后台入口"inurl:login":查找包含“login”的登陆页面"inurl:php?id=":查找可能存在SQL注入漏洞的PHP页面"inurl:asp?id=":查找可能存在ASP注入漏洞的PHP页面"inurl:jsp?id=":查找可能存在JSP注入漏洞的PHP页面......
  • 多核异构模式下有管理的共享内存设计方法
    随着嵌入式系统、高性能计算和物联网技术的飞速发展,多核异构处理器已经成为当前计算平台的重要组成部分。多核异构处理器通过集成多种类型的处理器核心(如高性能CPU核心、GPU核心、NPU核心等),能够同时满足高性能计算和节能降耗的需求。然而,多核异构处理器的设计也带来了新的挑战,尤其......
  • Java独门秘籍:如何用单例模式炼成“独孤求败”
    前言在江湖之中,“独孤求败”不仅是实力的象征,更是对“绝对”的追求,如同巅峰高手俯瞰四方。转眼来到Java的编程江湖,单例模式恰似那传说中的“独孤求败”,以其无与伦比的威力统领着资源管理的战场。它确保一个类只存在唯一的实例,如同武林至尊般静坐于山巅,稳如泰山,任凭风雨侵袭,依......
  • 线程安全的单例模式(Singleton)。
    在Java中,实现线程安全的单例模式(Singleton)通常涉及确保类的实例在多线程环境中只被创建一次。有多种方法可以实现这一点,包括使用synchronized关键字、双重检查锁定(Double-CheckedLocking,DCL)、静态内部类(BillPughSingletonDesign)以及使用java.util.concurrent包中的类。......