Java两大工具库:Commons和Guava(6)

简介: 除了操作集合、限流和缓存,Guava还有另一个隐秘的功能:事件总线EventBus机制——是发布-订阅模式的实现,不需要显式地注册回调——比观察者模式更灵活。

除了操作集合、限流和缓存,Guava还有另一个隐秘的功能:事件总线EventBus机制——是发布-订阅模式的实现,不需要显式地注册回调——比观察者模式更灵活。
EventBus是在单体架构内实现松耦合的一种很好的手段,通过它可以实现与业务逻辑无关的事件监听和消费。Guava提供的事件总线EventBus分为两种:
1、同步事件EventBus,主要用于单线程环境;
2、异步事件AsyncEventBus,主要用于多线程环境。
可以稍稍回顾一下观察者模式。
在支付系统的设计模式中,当完成交易后,需要给用户发送通知时就使用到了观察者模式,怎么做的呢?
1、定义账户观察者接口及其子接口支付观察者和积分观察者;
2、支付抽象类实现这两个子接口,具体支付类阿里支付、微信支付和余额支付,也都分别实现这两个子接口;
3、在账户类中加入观察者接口列表,并增加注册、删除和调用观察者接口的方法;
4、在支付时将各类支付方式注册到账户的观察者列表中;
5、在交易完成后,就可以调用账户的调用观察者接口的方法,实现回调。

 
观察者模式的实现稍嫌麻烦。
既然用观察者模式实现比较麻烦,那不妨换个思路,用Guava EventBus来实现,而且无需继承任何接口。调用、发送回调通知同样也很简单,用EventBus把支付回调再来实现一遍。
先定义观察者:
/**

  • 支付宝观察者

*

  • @author 湘王

*/
public class AliPayObserver {

// 标记当前订阅者是线程安全的,支持并发接收消息
@AllowConcurrentEvents
@Subscribe
public void pay(Account account) {
    if (account.getName().equalsIgnoreCase("ALI")) {
        System.out.println("支付宝 >>>>>> 已付款");
        System.out.println(account.getMessage());
    }
}

}
复制代码
 
/**

  • 微信支付观察者

*

  • @author 湘王

*/
public class WeixinObserver {

// 标记当前订阅者是线程安全的,支持并发接收消息
@AllowConcurrentEvents
@Subscribe
public void pay(Account account) {
    if (account.getName().equalsIgnoreCase("WEIXIN")) {
        System.out.println("微信 >>>>>> 已付款");
        System.out.println(account.getMessage());
    }
}

}
复制代码
/**

  • 余额支付观察者

*

  • @author 湘王

*/
public class YuePayObserver {

// 标记当前订阅者是线程安全的,支持并发接收消息
@AllowConcurrentEvents
@Subscribe
public void pay(Account account) {
    if (account.getName().equalsIgnoreCase("YUE")) {
        System.out.println("余额 >>>>>> 已付款");
        System.out.println(account.getMessage());
    }
}

}
复制代码
然后定义账户类:
/**

  • 账户

*

  • @author 湘王

*/
public class Account {

private String name;
private double amount;
private Date date;

public Account(String name, double amount, Date date) {
    this.name = name;
    this.amount = amount;
    this.date = date;
}

public String getName() {
    return name;
}

public String getMessage() {
    StringBuilder sb = new StringBuilder();
    sb.append("账户:").append(this.name).append(", ");
    sb.append("金额:").append(amount).append(", ");
    sb.append("日期:").append(date);
    return sb.toString();
}

}
复制代码
 
最后实现事件总线:
/**

  • 事件总线

*

  • @author 湘王

*/
public class EventBusTest {

// 回调通知
public static void notifyObserver() {
    EventBus bus = new EventBus();
    AliPayObserver ali = new AliPayObserver();
    WeixinObserver weixin = new WeixinObserver();
    YuePayObserver yue = new YuePayObserver();
    bus.register(ali);
    bus.register(weixin);
    bus.register(yue);

    Account account1 = new Account("ALI", 1.6, new Date());
    bus.post(account1);
    Account account2 = new Account("WEIXIN", 2.2, new Date());
    bus.post(account2);
    Account account3 = new Account("YUE", 3, new Date());
    bus.post(account3);
}

public static void main(String[] args) throws InterruptedException {
    notifyObserver();
}

}
复制代码
 
运行main方法,可以看到,尽管没有显式声明观察者接口,但通过一个@Subscribe注解,就完成了方法回调。这就是EventBus比观察者模式要灵活强大的地方。
 
如果还不满足,那就再来一个例子。创建观察者接口和具体观察者:
/**

  • 做家务的接口

*

  • @author 湘王

*/
public interface HouseWork {

public void dry();

}
复制代码
 
/**

  • 女主人(具体做家务的人)

*

  • @author 湘王

*/
public class Woman implements HouseWork {

@Override
public void dry() {
    System.out.println("可以晾衣服了");
}

}
复制代码
 
创建Subject:
/**

  • 洗衣机(Subject类)

*

  • @author 湘王

*/
public class WashingMachine {

private Vector<HouseWork> vector = new Vector<>();

public void register(HouseWork work) {
    vector.add(work);
}

public void unregister(HouseWork work) {
    vector.remove(work);
}

public void notifyObserver() {
    for (HouseWork work : vector) {
        work.dry();
    }
}

public static void main(String[] args) throws InterruptedException {
    // 洗衣机
    WashingMachine machine = new WashingMachine();
    // 女主人
    Woman woman = new Woman();
    // 洗衣机让女主人成为自己的观察者
    machine.register(woman);
    System.out.println("将衣服放到洗衣机。。。");
    System.out.println("买菜、遛娃中。。。");
    Thread.sleep(3000);
    // 通知观察者(女主人),衣服洗完了
    machine.notifyObserver();
}

}
复制代码
 
用EventBus把刚才家庭妇女做家务的例子再来做一遍(现在换成家庭妇男):
/**

  • 具体观察者

*

  • @author 湘王

*/
public class Man {

@Subscribe
public void dry(Sheet sheet) {
    System.out.println("可以晾 " + sheet.getName() + " 床单了");
}

}
复制代码
 
/**

  • 事件总线

*

  • @author 湘王

*/
public class EventBusTest {

// 回调通知
public static void notifyObserver() {
    EventBus bus = new EventBus();
    Man man = new Man();
    bus.register(man);
    bus.post(new Sheet("富安娜"));
}

public static void main(String[] args) {
    notifyObserver();
}

}
复制代码
 
/**

  • 床单实体类

*

  • @author 湘王

*/
public class Sheet {

private String name;

public Sheet(String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}
复制代码
 
运行main方法,可以看到和之前一样的效果。事件总线的一个缺点是,回调接口必须有参数——这并不友好。

相关文章
|
6天前
|
人工智能 缓存 监控
使用LangChain4j构建Java AI智能体:让大模型学会使用工具
AI智能体是大模型技术的重要演进方向,它使模型能够主动使用工具、与环境交互,以完成复杂任务。本文详细介绍如何在Java应用中,借助LangChain4j框架构建一个具备工具使用能力的AI智能体。我们将创建一个能够进行数学计算和实时信息查询的智能体,涵盖工具定义、智能体组装、记忆管理以及Spring Boot集成等关键步骤,并展示如何通过简单的对话界面与智能体交互。
110 1
|
6月前
|
JavaScript 前端开发 Java
通义灵码 Rules 库合集来了,覆盖Java、TypeScript、Python、Go、JavaScript 等
通义灵码新上的外挂 Project Rules 获得了开发者的一致好评:最小成本适配我的开发风格、相当把团队经验沉淀下来,是个很好功能……
1167 103
|
6月前
|
监控 Java Unix
6个Java 工具,轻松分析定位 JVM 问题 !
本文介绍了如何使用 JDK 自带工具查看和分析 JVM 的运行情况。通过编写一段测试代码(启动 10 个死循环线程,分配大量内存),结合常用工具如 `jps`、`jinfo`、`jstat`、`jstack`、`jvisualvm` 和 `jcmd` 等,详细展示了 JVM 参数配置、内存使用、线程状态及 GC 情况的监控方法。同时指出了一些常见问题,例如参数设置错误导致的内存异常,并通过实例说明了如何排查和解决。最后附上了官方文档链接,方便进一步学习。
658 4
|
5月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
191 0
|
4月前
|
Java 数据安全/隐私保护 计算机视觉
银行转账虚拟生成器app,银行卡转账截图制作软件,java实现截图生成工具【仅供装逼娱乐用途】
本内容提供Java生成自定义图片的示例代码,涵盖基础图像创建、文本添加及保存功能,适合学习2D图形编程。包括教学示例图片生成、文本图层处理和数字水印技术实现方案。
|
4月前
|
安全 Java 编译器
JD-GUI,java反编译工具及原理: JavaDecompiler一个Java反编译器
Java Decompiler (JD-GUI) 是一款由 Pavel Kouznetsov 开发的图形化 Java 反编译工具,支持 Windows、Linux 和 Mac Os。它能将 `.class` 文件反编译为 Java 源代码,支持多文件标签浏览、高亮显示,并兼容 Java 5 及以上版本。JD-GUI 支持对整个 Jar 文件进行反编译,可跳转源码,适用于多种 JDK 和编译器。其原理基于将字节码转换为抽象语法树 (AST),再通过反编译生成代码。尽管程序可能带来安全风险,但可通过代码混淆降低可读性。最新版修复了多项识别错误并优化了内存管理。
1954 1
|
4月前
|
Java 数据安全/隐私保护
银行转账虚拟生成器app,银行卡转账截图制作软件,java实现截图生成工具【仅供装逼娱乐用途】
本项目提供了一套基于Java的图片处理教学方案,包含自定义图片生成、图像水印添加及合法电子凭证生成技术示例。
|
11月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
211 9
|
10月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
1983 65
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
11月前
|
SQL Java 索引
java小工具util系列2:字符串工具
java小工具util系列2:字符串工具
247 83