Google Guava:EventBus

发布时间 2023-12-18 20:00:17作者: 茄子_2008

EventBus是Guava中对于事件发布订阅功能的实现,是设计模式中的发布/订阅模式的一种实现方案。

功能概括:

通过eventBus.register注册订阅者,通过eventBus.post方法发布事件,然后根据发布事件的类型(classType),执行所有订阅者中被@Subcribe注解标记的且参数类型一致的方法,从而实现发布、订阅功能。

源码解读:

源码基于如下版本解析:

1
2
3
4
5
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>25.1-jre</version>
</dependency>

 

 

1. 通过eventBus.register()方法注册订阅者

2. 将该订阅者注册到该eventBus中,源码见findAllSubcribers(listener)方法。在这个过程中,会查找到被注册类中被@Subcribe注解标记的方法,并将这些方法按照 入参类型,添加到Multimap<class<?>, Subcriber>中

 

 

3. 通过eventBus.post()方法发布事件,根据事件类型找到所有对应subcriber,遍历;然后由eventBus中的线程池执行订阅者中入参类型匹配的方法。

简单实用示例:

在springboot中,使用自动注入的方式来实现

目录结构:

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package com.example.demo.eventbus.config;

import com.google.common.eventbus.EventBus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 注入eventBus bean
 *
 */
@Configuration
public class EventBusConfig {

    @Bean("eventBus")
    public EventBus eventBus() {
        return new EventBus("demo");
    }
}


package com.example.demo.eventbus.listener;

import com.google.common.eventbus.EventBus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Map;

/**
 * 注册eventListener
 *
 */
@Component
public class ApplicationListenerRegister implements ApplicationListener<ContextRefreshedEvent> {

    @Autowired
    private EventBus eventBus;

    @Autowired
    private ConfigurableApplicationContext context;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        Map<String, IEventListener> listenerMap = context.getBeansOfType(IEventListener.class);
        if (!CollectionUtils.isEmpty(listenerMap)) {
            for (Map.Entry<String, IEventListener> entry : listenerMap.entrySet()) {
                eventBus.register(entry.getValue());
                System.out.println("eventListener registed: " + entry.getValue().getClass());
            }
        }
    }
}


package com.example.demo.eventbus.listener;

/**
 * 事件监听者接口
 *
 */
public interface IEventListener {
}


package com.example.demo.eventbus.listener;

import com.google.common.eventbus.Subscribe;
import org.springframework.stereotype.Component;

/**
 * 监听Integer
 *
 */
@Component
public class ListenerInt implements IEventListener{

    @Subscribe
    public int call(Integer num) {
        System.out.println("ListenerInt call(): " + num);
        return num;
    }

}


package com.example.demo.eventbus.listener;

import com.google.common.eventbus.Subscribe;
import org.springframework.stereotype.Component;

/**
 * 监听字符串事件
 *
 */
@Component
public class ListenerStr implements IEventListener{

    @Subscribe
    public String call(String str) {
        System.out.println("ListenerStr call() : " + str);
        return str;
    }

    @Subscribe
    public String call2(String str) {
        System.out.println("ListenerStr call2() : " + str);
        return str;
    }
}


package com.example.demo.eventbus;

import com.google.common.eventbus.EventBus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * eventBus测试
 *
 */
@RestController
@RequestMapping("/event")
public class EventBusTestController {


    @Autowired
    private EventBus eventBus;

    @GetMapping("/eventTest")
    public void eventTest() {
        System.out.println("eventTest started");
        eventBus.post("string test");

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        eventBus.post(111);
        System.out.println("eventTest end");
    }
}

运行结果:

 

 

 

附带介绍下Java  guava工具包:

 

Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你的JAVa代码更加优雅,更加简洁,让你工作更加轻松愉悦。下面我们就开启优雅Java编程学习之旅!

  项目相关信息:

  官方首页:http://code.google.com/p/guava-libraries
  官方下载:http://code.google.com/p/guava-libraries/downloads/list
  官方文档:http://docs.guava-libraries.googlecode.com/git/javadoc
http://www.ostools.net/apidocs/apidoc?api=guava

  源码包的简单说明:
  com.google.common.annotations:普通注解类型。
  com.google.common.base:基本工具类库和接口。
  com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。
  com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。
  com.google.common.eventbus:发布订阅风格的事件总线。
  com.google.common.hash: 哈希工具包。
  com.google.common.io:I/O工具包。
  com.google.common.math:原始算术类型和超大数的运算工具包。
  com.google.common.net:网络工具包。
  com.google.common.primitives:八种原始类型和无符号类型的静态工具包。
  com.google.common.reflect:反射工具包。
  com.google.common.util.concurrent:多线程工具包。

  类库使用手册:

  一. 基本工具类:让使用Java语言更令人愉悦。

  1. 使用和避免 null:null 有语言歧义, 会产生令人费解的错误, 反正他总是让人不爽。很多 Guava 的工具类在遇到 null 时会直接拒绝或出错,而不是默默地接受他们。
  2. 前提条件:更容易的对你的方法进行前提条件的测试。
  3. 常见的对象方法: 简化了Object常用方法的实现, 如 hashCode() 和 toString()。
  4. 排序: Guava 强大的 "fluent Comparator"比较器, 提供多关键字排序。
  5. Throwable类: 简化了异常检查和错误传播。

  二. 集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。

  1. Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。
  2. New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps等等
  3. Powerful collection utilities(强大的集合工具类): java.util.Collections 中未包含的常用操作工具类
  4. Extension utilities(扩展工具类): 给 Collection 对象添加一个装饰器? 实现迭代器? 我们可以更容易使用这些方法。

  三. 缓存: 本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。

  四. Functional idioms(函数式): 简洁, Guava实现了Java的函数式编程,可以显著简化代码。

  五. Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码。

  1. ListenableFuture(可监听的Future): Futures,用于异步完成的回调。
  2. Service: 控制事件的启动和关闭,为你管理复杂的状态逻辑。

  六. Strings: 一个非常非常有用的字符串工具类: 提供 splitting,joining, padding 等操作。

  七. Primitives: 扩展 JDK 中未提供的对原生类型(如int、char等)的操作, 包括某些类型的无符号的变量。

  八. Ranges: Guava 一个强大的 API,提供 Comparable 类型的范围处理, 包括连续和离散的情况。

  九. I/O: 简化 I/O 操作, 特别是对 I/O 流和文件的操作, for Java 5 and 6.

  十. Hashing: 提供比 Object.hashCode() 更复杂的 hash 方法, 提供 Bloom filters.

  十一. EventBus: 基于发布-订阅模式的组件通信,但是不需要明确地注册在委托对象中。

  十二. Math: 优化的 math 工具类,经过完整测试。

  十三. Reflection: Guava 的 Java 反射机制工具类。