读源码练内功(一):guava之eventbus

EventBus的使用及 解决异常Subscriber ****has no public methods called ** 最近才接触到EventBus这个组件,发现它真的很好用,正准备使用到项目中去。EvenBus简化了应用程序内各组件间、组件与后台线程间的通信。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。它的效果和Handler的效果大致相同,但是实现原理和使用方法是完全不同的,它是基于保存相应 阅读详情

现在如今眼目下,开源程序库越来越多,程序员们很多时候都不需要自己造轮子,就可以找到称心如意的开源库进行使用。虽然我们在使用各种各样的开源代码时,并不需要知道这些代码是如何实现的。但是了解它们的实现方法,不仅可以提升我们自己本身的编程能力和编程技巧,同时也为我们学习某一特定的技术点提供了可以模仿的例子。


Guava简介

如同boost之于c++,guava也几乎成为了java编程中不可或缺的一部分。guava中涵盖了很多有意思的东西,比如在java中使用函数式编程;新的数据结构,如bimap等等。总之,guava让写java程序成为一件更美好的事情。guava中还有很多很多有意思的东西,可以去guava的官方网站上探个究竟。guava

本文试图通过分析guava的eventbus的源代码,学习如何在java中使用annotation编程。

EventBus简介

Publisher-Subscriber这种设计模式在GoF中早就详细的解释。也是一种最常用不过的设计模式。而EventBus则是对于Publisher和Subscriber的一种实现,如果你还在使用JDK中的Observer,则不妨看看TW大大的一片博客《你应该更新的java知识之observer》,使用EventBus替代Observer似乎成了一种必须。

EventBus使用方法

MessageScreen.java:

public class MessageScreen {
    @Subscribe
    public void printMessage(String message) {
        System.out.println(message);
    }
}

调用代码:

        EventBus eventBus = new EventBus();
        eventBus.register(new MessageScreen());
        eventBus.post("Hello Screen");

显示结果:

     Hello Screen


代码解释:

调用eventBus中得register时,会向eventBus中注册一个Listener。这里的listener就是MessageScreen。

listener中被@Subscribe标示的方法为EventHandler,当eventBus使用post发布Event时,这个方法就会被调用。对应前面的例子,EventHandler是printMessage这个方法。Event是“Hello Screen”。

EventHandler中的参数类型为EventType,这里是String。当eventBus使用post时,会更具event的Type不同发送到相应的handler进行处理。

于是,一切看似神奇的事情都是发生在@Subscribe这个标记上。那Annotation究竟是干什么用得呢?怎么的一个标明了@Subscribe的方法就可以变成了一个subscriber了呢?


Annotation编程

Annotation是一种元数据,它提供了关于程序的信息,但是这个信息并不属于被Annotation标注的程序的本身的一部分。它不会影响被标注的程序的执行。

以上面的MessageListener为例,displayMessage这个方法被标注了@Subscribe,这个标注信息是在EventBus中的register中用到的,而不是在MessageListener中用到的。

Annotation编程可以分为大致两个部分,第一个部分是annotation定义,第二个部分是获取被annotation标记的代码,然后针对这部分代码进行一些特定的操作。下面就使用EventBus讲解这两个部分的工作是如何完成的。

定义Annotation:@Subscribe

Subscribe的定义:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Subscribe {
}


@interface表示定义了一个annotation。@Retention和@Target是predefined annotation。

@Retention表示Subscribe这个Annotation是怎么被保存的。@Retention(RententionPolicy.RUNTIME)说明Subscribe这个annotation在运行时可以被使用。

@Target表示的是这个Subscribe这个annotation能被标注到哪里。@Target(ElementType.METHOD)说明Subscribe是用于标记方法的。对应一开始EventBus的例子,就是printMessage这个方法。


获取被Annotation标记的代码:EventBus中如何知道@Subscribe的方法的呢?

EventBus的代码:

    public void register(Object object) {
        Multimap<Class<?>, EventHandler> methodsInListener =
                finder.findAllHandlers(object);
        handlersByType.putAll(methodsInListener);
    }

在EventBus进行register时,会通过一个finder找到register的object中被标注了@Subscribe的方法。并且按照EventType进行分类,放在handlersByType里。这样当EventBus的post新的Event时,就可以根据EventType调用相应的EventHandler。

AnnotatedHandlerFinder的代码:

     public Multimap<Class<?>, EventHandler> findAllHandlers(Object listener) {
         Multimap<Class<?>, EventHandler> methodsInListener = HashMultimap.create();
         Class<?> clazz = listener.getClass();
         for (Method method : getAnnotatedMethods(clazz)) {
             Class<?>[] parameterTypes = method.getParameterTypes();
             Class<?> eventType = parameterTypes[0];
             EventHandler handler = makeHandler(listener, method);
             methodsInListener.put(eventType, handler);
         }
         return methodsInListener;
     }

在findAllHandlers这个函数中,将首先调用getAnnotatedMethods得到listener中所有被标记了@Subscribe的方法。然后将listener和被标记了@Subscribe的方法本身放在一个叫EventHandler的数据结构中,同时记录了method的第一个也是唯一一个参数类型作为EventType作为post时按类型分发消息使用。接着再看是如何得到被@Subscribe标记的方法的:

    private static ImmutableList<Method> getAnnotatedMethods(Class<?> clazz) {

            for (Method method : clazz.getMethods()) {
                if (method.isAnnotationPresent(Subscribe.class)) {
                    ... ...// add to list
                }
            }
        }

getAnnotatedMethods首先获得了listener的所有方法。然后再遍历查询是否有方法是否被@Subscribe标示了:method.isAnnotationPresent(Subscribe.class)。如果被@Subscribe标示了,则添加到返回的list中。这其实也告诉了我们,这种方法的另一个好处,一个类中不再只能有一个update作为Observer的方法。而是可以有多个被@Subscribe标示的EventHandler,他们在同一个类时,就通过方法名和EventType进行区分。


当EventBus中的post被调用时,中间会有一系列的入队列,出队列的操作。最后调用,Eventhandler的handleEvent方法。

EventHandler.java

public void handleEvent(Object event) {
        method.invoke(target,new Object[]{ event});
        }

handleEvent中method是在register中被标记了@Subscribe的方法,第一个参数target就是在register中加入的listener,通过调用method的invoke方法。这样就调用了被@Subscribe的方法。


总结

1.Annotation编程在很多地方都有用到,比如大家都再熟悉不过的Junit4中的@Test,Spring中的@Component等等。所以,学习Annotation,说不定可以让我们写出这些使用方便的程序。

2.在EventBus的完整实现中,其实还包含了其他很多的技术,像多线程、cache以及Guava其他的一些功能。比如getAnnotatedMethods这个方法并不是真正的去查找Annotated Methods,真正的查找是getAnnotatedMethodsInternal这个方法,期间就使用了cache。这里想专注于Annotation本身的使用,就不展开讨论了。

3.在判断是否含有@Subscribe时,AnnotatedHandlerFinder实际上是检查了所有父类的方法。因为父类本身的Annotation是不会被子类继承的,如果子类重写了父类的方法。那么调用子类的isAnnotationPresent则会返回false。

4. 如何想要了解更多的关于annotation的细节知识,可以访问下oracle的官方文档:oracle annotation


基于Guava API实现异步通知和事件回调,Java需要掌握的技能 每年转战互联网行业的人很多,说白了也是冲着高薪去的,不管你是即将步入这个行业还是想转行,学习是必不可少的。作为一个Java开发,学习成了日常生活的一部分,不学习你就会被这个行业淘汰,这也是这个行业残酷的现实。如果你对Java感兴趣,想要转行改变自己,那就要趁着机遇行动起来。或许,这份限量版的Java零基础宝典能够对你有所帮助。轻大家的负担。**[外链图片转存中…(img-qyJZFJMv-1711104204511)][外链图片转存中…(img-ZKCehq1m-1711104204512)] 阅读详情

相关推荐

guava之EventBus

观察者模式 这个讲的地方特别多,随便百度就好,这里随意贴了一个别人的链接 http://c.biancheng.net/view/1390.html 解决的问题 观察者模式解决的场景就是:解耦。将一些和主业务逻辑不强相关的逻辑可以解耦出来,统一处理。 Eventbus EventBus提供了两种观察方式:同步和异步 同步方式:post()和对应的事件处理器EventHandler逻辑在同一个线程执行。 异步方式:事件处理器EventHandler逻辑在指定线程池中执行,和post()事件的线

sinat_14913533的博客 2021

[置顶] 读源码练内功(一):guava之eventbus

现在如今眼目下,开源程序库越来越多,程序员们很多时候都不需要自己造轮子,就可以找到称心如意的开源库进行使用。虽然我们在使用各种各样的开源代码时,并不需要知道这些代码是如何实现的。但是了解它们的实现方法,不仅可以提升我们自己本身的编程能力和编程技巧,同时也为我们学习某一特定的技术点提供了可以模仿的例子。 Guava简介 如同boost之于c++,guava也几乎成为了java编程中不可或...

weixin_30823227的博客 272

Guava事件总线EventBus阻塞行为解读

google guava库的事件总线组件EventBus,是观察者模式(进程内事件发布/订阅)的一个比较优雅的实现。之前项目一直没什么机会使用(之前事件解耦多用消息中间件),最近自个儿摸索DDD,在进程内领域事件的实现时,采用了EventBus,总体使用比较顺利,其提供的api也比较简单,在这里就不详诉使用方式了。今天就如标题所说,谈谈EventBus post事件时的阻塞行为。 具体遇到的令我困惑的行为是,在不同线程里post事件,貌似也会相互阻塞。以下是实验代码: public static void

u014249527的博客 1912

深入理解Guava EventBus实现思想和实际用法

一、写在前面 随着企业业务趋向复杂,往往会碰到以下情况 在一个类中需要和多个其他类进行关联,造成类与类之间的耦合严重。 多处地方有相同的逻辑,造成代码重复性。 而有效的解耦方式就是使用事件机制,它主要的实现思想就是观察者模式。观察者模式主要涉及到三个概念:事件、订阅者和发布者。简单可以理解为发布者发布事件,订阅者消费对应的事件。 实现本地事件机制的有Guava的eventBus,Spring的Event。本文我主要想介绍一下Guava的eventBus。 二、传统的观察者模式 为啥这里需要先说一下传统的

曳凡的博客 1655

Google Guava EventBus使用

Guava是Google开源的一个Java基础类库,它在Google内部被广泛使用。Guava提供了很多功能模块比如:集合、并发库、缓存等,EventBus是其中的一个module,本篇主要讲一下EventBus的使用。 简单介绍 EventBus:核心类,代表了一个事件总线。Publish事件也由它发起。 AsyncEventBus:异步事件总线,在分发事件的时候,将其压入一个全局队列的异步分发模式。 Subscriber:对某个事件的处理器抽象,封装了事件的订阅者以及处理器,并负责事件处理。

流子的专栏 1211

别再让COGI拖慢你的SAP接口!手把手教你配置BAPI_PRODORDCONF_CREATE_TT的同步货物移动

本文深入解析SAP生产订单报工接口中的COGI问题,通过BAPI_PRODORDCONF_CREATE_TT的同步配置实战,解决异步更新导致的性能瓶颈。文章详细介绍了增强点配置和性能验证,帮助用户彻底消除COGI堆积,提升接口效率。

weixin_29214691的博客 482

Guava Event Bus 详解

是的,很像,但是EventBus是JVM内部的事件总线,适合应用内部的解耦,如果应用很大,大家会使用微服务拆分进行解耦,微服务之间的消息通信会使用Kafka、RabbitMQ等等消息中间件,当然如果流量很大,需要削峰填谷,会部署多个实例,通过消息中间件实现多个应用实例之间消息的负载均衡。EventBus是google的Guava库中的一个处理JVM内部组件间通信的事件总线,它基于发布/订阅模式,实现了多组件之间通信的解耦合,事件产生方和事件消费方实现解耦分离,提升了通信的简洁性。

m0_61089765的博客 2062

EtherCAT FOE从站开发实战:SSC工具包实现固件在线升级与文件传输

EtherCAT从站开发中,固件在线升级与文件传输是常见需求。FOE(File Access over EtherCAT)作为邮箱通信协议,在实时总线上提供可靠的文件读写通道,与PDO、DC同步共存。其原理基于SM邮箱和状态机,通过SSC工具包可快速启用。技术价值在于无需拆机即可更新固件、导出日志,提升产线效率。应用场景包括伺服驱动器、IO模块等从站的固件升级与参数配置。本文深入讲解从站侧FOE读写实现、主站调用及工程化建议,助力嵌入式工程师高效开发。

weixin_29169899的博客 127

Guava 12:Guava EventBus源码剖析

一、架构速读 传统上,Java的进程内事件分发都是通过发布者和订阅者之间的显式注册实现的。设计EventBus就是为了取代这种显示注册方式,使组件间有了更好的解耦。EventBus不是通用型的发布-订阅实现,不适用于进程间通信。 架构图如下: 。 二、简单使用 步骤如下: 1.构造一个事件总线 2.构造一个事件监听器 3.把事件监听器注册到事件总线上 4.事件总线发布事件,触发监...

博客园搬家测试账号 901

AWR1843+DCA1000通过mmwave studio采集数据遇到的问题及解决方法

确保DCA1000的拨钮拨在了RADAR_5V_IN一边,这代表DCA1000通过与其相连的雷达板子供电,如果拨到了DC_JACK5V_IN一边,表示DCA1000用单独的电源供电。

qq_50974341的博客 4163

C#上位机案例:西门子S7协议通信+实时曲线显示(WinForm+ZedGraph)

创建/// PLC数据模型(对应DB1块)/// 采集时间(用于曲线的X轴)set;/// 温度值(℃)set;/// 压力值(MPa)set;/// PLC通信状态set;西门子S7协议通信和实时曲线显示,也是工控现场最常见的场景之一。整个开发过程的关键不在于“写出代码”,而在于“写出符合工控场景的稳定代码”——比如解耦通信逻辑与界面逻辑、处理跨线程问题、限制数据点数量、释放资源等。新手在学习时,建议先跟着步骤搭建好环境,跑通基础功能,再逐步尝试进阶优化。需要注意的是,工控上位机的核心是。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1342

Google Guava EventBus(事件总线)

       EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式,EventBus非常优雅使用起来也非常的简单,这个可不是吹的是真的非常的简单。        EventBus内部实现原理不复杂(源码不复杂,强烈推荐大家去看下)。我们简单的...

旧路 2万+

从原理到实战:深入解析 Synopsys VCS 仿真快照技术,提升验证效率

VCS Checkpoint 技术摘要 VCS Checkpoint 是 Synopsys VCS 提供的仿真状态快照功能,可将完整的仿真状态(寄存器、存储器、时钟、随机种子等)序列化保存。主要应用场景包括:跳过耗时初始化阶段、覆盖率驱动验证、Debug复现和UVM分阶段验证。核心原理是对仿真内核状态的完整序列化,需注意文件句柄等特殊对象需手动处理。 使用方式: 编译时添加 -checkpoint 选项 运行时通过 $save 系统任务或 +checkpoint 参数保存状态 通过 +restore 参数恢

元直的博客 248

、【Guava】EventBus 源码解析

EventBus 采用发布订阅者模式的实现方式,它实现了泛化的注册方法以及泛化的方法调用,另外还考虑到了多线程的问题,对多线程使用时做了一些优化,观察者模式都比较熟悉,这里会简单介绍一下,重点介绍的是如何泛化的进行方法的注册以及调用,还有在单个线程和多线程不同的实现方式。#发布订阅者模式Guva中EventBus的机制就是观察者模式,因此符合观察者模式的一般结构:监听者:监听来自被监听者的变更事件,完成动作变更被监听者:发送变更事件给监听者,使监听者监听到变更事件后,完成动作变更。

成年老猿的专栏 1493

整车的智能配电系统

本文探讨了汽车电网安全的重要性,分析了传统汽车电网的现状,并重点介绍了半导体在汽车智能配电系统中的作用。半导体凭借其单向导电性和可控性,如二极管、MOSFET等,提供了更高效、安全的电力控制。通过对比传统保险丝与半导体器件,阐述了半导体在过流保护、电压监测和故障诊断方面的优势,强调其在减少安全隐患、提高能源管理和续航里程方面的贡献。极氪智能配电系统展示了如何运用半导体技术实现整车能源的精细化管理,降低维修成本,减少线束复杂性,提升安全性能。

让你爱上电路设计 1611

AUTOSAE软件配置-项目标准配置 (PSC) 导入达芬奇( DaVinci Configurator)

文件是“可拆分的”,这意味着如果格式符合 AUTOSAR 拆分规则,则可以与其他。)是一个ARXML文件,主要由OEM提供,其中包含。)工件,可以作为输入文件导入到达芬奇配置器专业版。导入的参数将以只读方式处理。不允许在多个 ARXML 文件中导入一个。的已存在数据或从输入文件派生的数据。可以作为输入文件导入到另一个。文件会覆盖用户配置的基本。元素和诊断数据预配置。定义 [数据结构]。中,可以导出一个或多个。

m0_49148264的博客 1005

Guava EventBus 源码解析

简介 Guava,谷歌出品的优秀脚手架,广泛应用于各大Java项目中,其源码也被称作《Effective Java》一书的最佳实践,值得广大程序员学习和参考。 EventBus,Guava 提供的事件总线,使得事件和订阅之间得到解耦,今天我们就来看看 EventBus 的使用方式和内部实现。 架构和组件图 使用方式 首先,添加 Guava 依赖 <dependency> <groupId>com.google.guava</groupId> <ar

haohong725的专栏 560

使用 Simulink 进行电力电子系统的大信号模型仿真

电力电子系统(Power Electronics System)包括各种功率转换器(如 DC-DC 转换器、逆变器等)。这些设备中的关键组件(如 MOSFET、IGBT、电容器、电感器等)不仅影响系统的性能,还直接关系到系统的稳定性、效率和可靠性。因此,在设计阶段进行详细的建模和仿真至关重要。大信号模型仿真的目的是通过模拟系统在非线性条件下的真实行为,评估其瞬态响应、稳态性能以及对不同负载和输入电压变化的响应。通过本教程,我们介绍了如何使用 Simulink 进行电力电子系统的大信号模型仿真。背景介绍。

xiaoheshang_123的博客 303

Google-Guava-EventBus源码解读

Guava是Google开源的一个Java基础类库,它在Google内部被广泛使用。Guava提供了很多功能模块比如:集合、并发库、缓存等,EventBus是其中的一个module,本篇结合EventBus源码来谈谈它的设计与实现。

VinoYang的专栏 1万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

观察者模式与事件驱动 —— Spring Event & Guava EventBus 深度解析

观察者模式本质:事件驱动解耦Spring Event:企业级、自动化、容器化Guava EventBus:轻量级、独立、易集成设计要点:注册监听、事件发布、类型匹配、反射回调、异常隔离、同步异步实战关注:链路调试、性能优化、异常处理、与中间件集成。

IT技术学习与工作笔记分享 1922

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Guava异步事件EventBus解析

EventBus源码分析 EventBus是guava提供的适用于进程间的消息通信的一个工具,常常用于轻量级的异步数据同步场景。使用EventBus可以使得业务逻辑解耦,并进行公用逻辑的抽象,一定程度上精简了业务代码。 EventBus使用说明 1)引入依赖 2)编写工具类如下: import com.google.common.eventbus.EventBus; import org.springframework.stereotype.Component; @Component @SuppressW

qq_16410733的博客 1498

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

guava EventBus 学习二 源码

上篇介绍了guava包中的event bus的使用, 本篇深入源码了解实现细节 EventBus 了解 首先当然要看EventBus类, 类上的注释说了很多, 总结如下: 1 EventBus保证在多线程环境下, 不会同时访问订阅者, 除非订阅者标注了AllowConcurrentEvents注解. 如果没有使用这个注解, 订阅者不需要担心消息重入的问题. 2 消息接收方法只能接收一个参数, 而且会根据消息类型路由消息到指定的订阅者. 如果消息类型存在父子关系, 那么发送子类消息, 父类订阅者也会收到. 3

明知道路正确,为何不全力以赴~.~ 470

Guava EventBus源码分析(二):注册订阅者方法

Guava EventBus源码分析(二):注册订阅者方法[TOC] Guava EventBus是一个发布-订阅模式的组件通信,但组件不需要显式地注册到其它组件中。 本文关注EventBus注册订阅者方法源码分析。一、概述:首先回顾一下第一讲提到的EventBus的三个核心方法。public class EventBus { //注册订阅者方法 public void register

Kindevil_的专栏 906

java guava eventbus_JAVA | Guava EventBus 使用

JAVA | Guava EventBus 使用 系列文章目录Table of Contents[TOC]前言EventBus 是 Guava 的事件处理机制,是观察者模式(生产/消费模型)的一种实现。观察者模式在我们日常开发中使用非常广泛,例如在订单系统中,订单状态或者物流信息的变更会向用户发送APP推送、短信、通知卖家、买家等等;审批系统中,审批单的流程流转会通知发起审批用户、审批的领导等等...

weixin_33940031的博客 453

Guava EventBus 源码分析

前言 EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。 EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和接口层次结构。 传统上,Java的进程内事件分发都是通过发布者和订阅者之间的显式注册实现的。设计EventBus就是为了取代这种显示注册方式,使组件间有了更好的解耦。 EventBus不是通用型的发布-订阅实现,不适用于...

小张的专栏 741
上一篇: Java中编写可变长参数的函数
下一篇: 1+1/1+1/2+1/3 + ...+1/16的整数部分是多少?
kiwi小白
博客等级 码龄14年 153粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值