【实用工具】Guava EventBus(事件总线)快速入门

news2024/12/27 12:58:12

介绍

EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。

Java案例

引入依赖

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.1-jre</version>
        </dependency>

定义消息类

@Data
@AllArgsConstructor
public class TestEvent {
    String message;
}

定义接收者

@Slf4j
public class DevmEventListener {

    @Subscribe
    public void handleTestEvent(TestEvent testEvent) {
        log.info("信息处理={}", testEvent);
    }

    @Subscribe
    public void greet(String greetInfo) {
        log.info("hello world {}", greetInfo);
    }
}

发送消息

public class SimpleMain {

    public static void main(String[] args) {

        EventBus eventBus = new EventBus("test");
        DevmEventListener listener = new DevmEventListener();

        eventBus.register(listener);

        eventBus.post(new TestEvent("200"));
        eventBus.post("charles");
    }
}

SpringBoot示例

定义注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBusListener {
}

定义事件

@Data
@Builder
public class ViewEvent {

    private String shortUrl;
}

事件监听者

@Component
@Slf4j
@EventBusListener
public class ViewEventListener {

    @Subscribe
    public void viewed(ViewEvent event) {
        String shortUrl = event.getShortUrl();
        log.info("url被访问" + shortUrl);
    }
}

定义EventBusCenter,获取所有的带有EventBusListener注册到AsyncEventBusEventBus,并且提供发布事件的接口。

@Component
public class EventBusCenter implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    // 管理同步事件
    private EventBus syncEventBus = new EventBus();

    // 管理异步事件
    private AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newCachedThreadPool());

    public void postSync(Object event) {
        syncEventBus.post(event);
    }

    public void postAsync(Object event) {
        asyncEventBus.post(event);
    }

    @PostConstruct
    public void init() {

        // 获取所有带有 @EventBusListener 的 bean,将他们注册为监听者
        Map<String, Object> objectMap = applicationContext.getBeansWithAnnotation(EventBusListener.class);
        List<Object> listeners = objectMap.entrySet().stream().map(entry -> entry.getValue()).collect(Collectors.toList());
        for (Object listener : listeners) {
            asyncEventBus.register(listener);
            syncEventBus.register(listener);
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

发送消息

@RestController
@Slf4j
public class TestController {

    @Autowired
    private EventBusCenter eventBusCenter;
    
    @GetMapping("/t1")
    public void t1() {
        eventBusCenter.postAsync(ViewEvent.builder().shortUrl("hh").build());
    }
}

框架示例

  1. 引入依赖
        <dependency>
            <groupId>com.nepxion</groupId>
            <artifactId>eventbus-aop-starter</artifactId>
            <version>2.0.15</version>
        </dependency>
  1. 启动类添加注解@EnableEventBus
  2. 添加监听者
@EventBus(async = false)
@Service
@Slf4j
public class MySubscriber1 {

    @Subscribe
    public void subscribe(String event) {
        log.info("子线程接收异步事件 - {},String类型", event);
    }
}
  1. 发布事件
@RestController
@Slf4j
public class TestController {

    @Autowired(required = false)
    private EventControllerFactory eventControllerFactory;

    @GetMapping("/publish")
    public void publish() {
        if (eventControllerFactory != null) {
            log.info("发送事件...");

            // 异步模式下(默认),子线程中收到派发的事件
            eventControllerFactory.getAsyncController().post("ASync Event String Format");

            // 同步模式下,主线程中收到派发的事件
            // 事件派发接口中eventControllerFactory.getSyncController(identifier)必须和@EnableEventBus参数保持一致,否则会收不到事件
            eventControllerFactory.getSyncController().post("Sync Event String Format");

        }
    }
}

原理解析

eventbus-aop-starter包中有spring.factories

com.nepxion.eventbus.annotation.EnableEventBus=\
com.nepxion.eventbus.configuration.EventConfiguration

EventConfiguration注入了EventControllerFactoryEventBeanPostProcessor

@Configuration
public class EventConfiguration {

	//...
    @Bean
    public EventControllerFactory eventControllerFactory() {
        return new EventControllerFactory();
    }

    @Bean
    public EventBeanPostProcessor eventBeanPostProcessor() {
        return new EventBeanPostProcessor();
    }

    @Bean
    public EventContextClosedHandler eventContextClosedHandler() {
        return new EventContextClosedHandler();
    }
}

EventBeanPostProcessor后置处理器,获取所有的监听者,注册到对应的EventController包装里面的EventBus

public class EventBeanPostProcessor implements BeanPostProcessor {
    @Autowired
    private EventControllerFactory eventControllerFactory;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean.getClass().isAnnotationPresent(EventBus.class)) {
            EventBus eventBusAnnotation = bean.getClass().getAnnotation(EventBus.class);
            String identifier = eventBusAnnotation.identifier();
            boolean async = eventBusAnnotation.async();

            eventControllerFactory.getController(identifier, async).register(bean);
        }

        return bean;
    }
}

EventControllerFactory,默认获取的是identifier=EventConstant.SHARED_CONTROLLER对应的EventController,从ConcurrentHashMap获取,没有就创建。如果是异步的,创建的是AsyncEventBus

public final class EventControllerFactory {
    @Autowired
    private ThreadPoolFactory threadPoolFactory;

    private volatile Map<String, EventController> syncControllerMap = new ConcurrentHashMap<String, EventController>();
    private volatile Map<String, EventController> asyncControllerMap = new ConcurrentHashMap<String, EventController>();

    public EventController getAsyncController() {
        return getAsyncController(EventConstant.SHARED_CONTROLLER);
    }

    public EventController getAsyncController(String identifier) {
        return getController(identifier, true);
    }

    public EventController getController(String identifier, boolean async) {
        return getController(identifier, async ? EventType.ASYNC : EventType.SYNC);
    }

    public EventController getController(String identifier, EventType type) {
        switch (type) {
            case SYNC:
                EventController syncEventController = syncControllerMap.get(identifier);
                if (syncEventController == null) {
                    EventController newEventController = createSyncController(identifier);
                    syncEventController = syncControllerMap.putIfAbsent(identifier, newEventController);
                    if (syncEventController == null) {
                        syncEventController = newEventController;
                    }
                }

                return syncEventController;
            case ASYNC:
                EventController asyncEventController = asyncControllerMap.get(identifier);
                if (asyncEventController == null) {
                    EventController newEventController = createAsyncController(identifier, threadPoolFactory.getThreadPoolExecutor(identifier));
                    asyncEventController = asyncControllerMap.putIfAbsent(identifier, newEventController);
                    if (asyncEventController == null) {
                        asyncEventController = newEventController;
                    }
                }

                return asyncEventController;
        }

        return null;
    }
    
    public EventController createSyncController(String identifier) {
        return new EventControllerImpl(new EventBus(identifier));
    }

    public EventController createAsyncController(String identifier, Executor executor) {
        return new EventControllerImpl(new AsyncEventBus(identifier, executor));
    }

EventControllerImpl实现了EventController,可以注册监听器,发布事件

public class EventControllerImpl implements EventController {
    private EventBus eventBus;

    public EventControllerImpl(EventBus eventBus) {
        this.eventBus = eventBus;
    }

    @Override
    public void register(Object object) {
        eventBus.register(object);
    }

    @Override
    public void unregister(Object object) {
        eventBus.unregister(object);
    }

    @Override
    public void post(Object event) {
        eventBus.post(event);
    }
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/544058.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

树莓派报错Oops - unable to determine board type . . .model:17

报错原因 改变方法 cd /tmp wget https://project-downloads.drogon.net/wiringpi-latest.deb sudo dpkg -i wiringpi-latest.deb成功

技术的力量:如何用数据驱动实现设备健康管理

在当今数字化时代&#xff0c;设备管理部门面临着日益复杂的挑战。传统的设备管理方法已经无法满足快速发展的需求&#xff0c;而数字化转型成为了提升效率、降低成本、增强竞争力的关键路径。 本文将介绍设备管理部门数字化转型的痛点、可参考的蓝图规划以及PreMaint平台在实现…

浅谈面向无线通信的微波毫米波无源天线及器件

一、背景 本文谈及的微波毫米波&#xff08;下简称微波&#xff09;产品主要是指工作在4&#xff5e;86GHz频段的无源天线和器件。它们使通信系统在不需要电源模块的情况下具备较高的动态范围和实现宽带模拟信道传输&#xff0c;属于现代点对点无线通信系统中核心天馈部件。文…

5年测试开发,跳槽薪资25k变成30k,总结的这些面试题,你会哪些?

每年的金三银四都是各大公司招聘程序员的最佳时期&#xff0c;在这段时间内有好多程序员会为了面试而发愁&#xff0c;不知道如何才能收到好的offer&#xff0c;拿到理想的薪资&#xff0c;实现自我的人生价值&#xff01; 我想告诉大家的是&#xff0c;其实都不用愁的&#xf…

AOSP构建、编译基础理解

AOSP构建、编译基础理解 构建系统 参考这篇文章&#xff0c;写的比较好&#xff0c;我就不狗尾续貂了&#xff01; android build system编译系统概述 source build/envsetup.sh之后的事情 source也就是执行build/envsetup.sh里面的脚本&#xff0c;改脚本定义许多命令&…

​GPT充当大脑,指挥多个模型协作完成各类任务,通用系统AutoML-GPT来了

使用 ChatGPT 实现通用人工智能&#xff0c;思路打开了。 当前&#xff0c;AI 模型虽然已经涉及非常广泛的应用领域&#xff0c;但大部分 AI 模型是为特定任务而设计的&#xff0c;它们往往需要大量的人力来完成正确的模型架构、优化算法和超参数。ChatGPT、GPT-4 爆火之后&…

ST典型碳化硅MOSFET驱动应用方案

ST典型碳化硅MOSFET驱动应用方案 1.栅极驱动器规格和功能实现 参考资料&#xff1a;ST官网应用手册《AN4671》 作者&#xff1a;Xiou 1.栅极驱动器规格和功能实现 以下是对栅极驱动要求的简短列表&#xff1a; dv / dt 的瞬变抗扰度&#xff1a;在整个温度范围内 50 V/ns。 …

超级简单的开源saas后台系统管理框架Vite+Vue3

大家好&#xff0c;今天我给大家带来一款超简saas后台管理系统框架&#xff0c;他是一款快速开发SAAS通用管理系统后台框架&#xff0c;前端采用最新的技术栈ViteTypeScriptVue3ElementPlus最流行技术架构&#xff0c;后台结合PHP8、Java SDK、Python等主流后端语言搭建&#x…

黑盒测试方法: 从原理到实战

文章目录 一. 如何设计测试用例二. 常用黑盒测试方法1. 基于需求设计的测试用例2. 等价类划分法3. 边界值4. 判定表分析法 (因果分析法)5. 正交排列6. 场景设计法7. 用例场景示例8. 错误猜测法 三. 补充案例Fiddler实现弱网测试水杯测试用例微信朋友圈测试用例淘宝购物车测试用…

ESP8266连接 TLink 云平台

1.硬件准备 &#xff08;1&#xff09;正点原子 ATK-ESP-01 WIFI 模块 &#xff08;2&#xff09;正点原子 STM32F103ZET6精英板子 &#xff08;3&#xff09;USB转TTL模块 2.烧录固件 &#xff08;1&#xff09;烧录软件和固件都可以在正点原子增值资料包找到。 &#xff08;2…

网络安全基础--dns劫持及IP信息收集

0x01 验证是否存在CDN 方法1&#xff1a; 很简单&#xff0c;使用各种多地 ping 的服务&#xff0c;查看对应 IP 地址是否唯一&#xff0c;如果不唯一多半是使用了CDN&#xff0c; 多地 Ping 网站有&#xff1a;多个地点Ping服务器,网站测速 - 站长工具网站测速工具_超级ping…

创建python虚拟环境的两种方法

创建python虚拟环境的两种方法 一、anaconda环境下1、检查是否安装了anaconda2、创建虚拟环境3、激活虚拟环境4、其他命令 二、python纯净环境下1. 安装virtualenv2. 创建虚拟环境3. 激活虚拟环境 一、anaconda环境下 1、检查是否安装了anaconda 只有在anaconda环境下才能创建…

近百个最新免费chatgpt访问集合,包含国内直接访问和国外升级版本

近百个最新免费chatgpt访问集合&#xff0c;包含国内直接访问和国外升级版本。 ChatGPT是一个基于人工智能的聊天机器人&#xff0c;它可以与用户进行自然语言交互。ChatGPT使用了最新的自然语言处理技术&#xff0c;包括深度学习和神经网络&#xff0c;以便更好地理解用户的…

慎投,5月有4本SCIE期刊被剔除(附SCI/SSCI目录下载)

2023年5月SCI、SSCI期刊目录更新 2023年5月18日&#xff0c;科睿唯安更新了WOS期刊目录&#xff0c;继上次4月WOS期刊目录剔除8本SCIE&SSCI期刊之后&#xff0c;此次5月更新又有4本SCIE期刊发生变动&#xff0c;其中有1本期刊被踢出SCIE数据库&#xff0c;3本期刊更改了名…

pdf怎么转换成ppt文件,5种方法任你选

pdf怎么转换成ppt文件&#xff1f;想必这是我们办公过程中非常常见的问题吧。众所周知&#xff0c;PDF文件格式通常用于存储文档&#xff0c;其内容可能是图像、文字或表格&#xff0c;展示在一个页面上。PPT文件格式通常用于创建演示文稿&#xff0c;其中每个页面都是幻灯片&a…

探秘音乐疗法——基于音乐的喂养环境对小鼠肠道菌群影响的研究

音乐对身心的影响 近年来&#xff0c;环境和动物生理及心理的相关研究越来越多。环境因素的丰富性和多样性是改善动物生理和心理状态的重要研究参数。 环境因素指的是正常环境&#xff0c;在这种环境中&#xff0c;动物通过获得环境激励以做出有益的增强&#xff0c;使它们能够…

怎么把两个pdf合并成一个?三种合并方法任你选择

PDF 格式是一种常见的跨平台文件格式&#xff0c;因此在日常生活和工作中&#xff0c;我们可能需要处理或编辑多个 PDF 文件&#xff0c;并将它们合并为一个文件&#xff0c;以方便查阅和共享。因此&#xff0c;将两个PDF文件合并是非常重要的。首先&#xff0c;两个PDF合并成一…

2023年最新整理渗透测试面试题

1、include、include_once、require、 require_once区别 参考答案&#xff1a; 1、require()和require_once()函数&#xff1a; &#xff08;1&#xff09;require()函数引入文件不存在时&#xff0c;将立即退出程序&#xff0c;不再向下执行。 &#xff08;2&#xff09;…

AD16中如何创建新工作空间

1、双击“DXP.exe” 如果默认安装&#xff0c;DXP.exe文件位于“C:\Program Files (x86)\Altium\AD16”目录下。 2、打开AD后&#xff0c;我们会看到默认工作空间为“Workspace1.DsnWrk” 3、在“F盘”下创建一个文件夹。命名为“AD16学习”。 4、点击“File-Save Design Work…

Git宝典

版本管理工具介绍 现在比较流行的版本管理工具是git&#xff0c;但是实际上git是近几年才发展起来的&#xff0c;可能有一些老的项目&#xff0c;还在用一些老的软件&#xff0c;如svn 版本管理发展简史 SVN&#xff08;SubVersion&#xff09; 工作流程 SVN是集中式版本控…