简单的消息组件:限定范围同一个jvm中
EventBus 是设计模式中的观察者模式(生产者/消费者编程模型)的实现。
EvenBus 中的相关术语
EventBus 术语 | 解释 | 备注 |
---|---|---|
事件(消息) | 可以向事件总线(EventBus)发布的对象 | 通常是一个类,不同的消息事件用不同的类来代替,消息内容就是类里面的属性 |
订阅 | 向事件总线注册监听者,以接受事件的行为 | EventBus.register(Object),参数就是监听者 |
监听者 | 提供一个处理方法,希望接受和处理事件的对象 | 通常也是一个类,里面有消息的处理方法 |
处理方法 | 监听者提供的公共方法,事件总线使用该方法向监听者发送事件;该方法应使用 Subscribe 注解 | 监听者里面添加一个 Subscribe 注解的方法,就可以认为是消息的处理方法 |
发布消息 | 通过事件总线向所有匹配的监听者提供事件 | EventBus.post(Object) |
EvenBus 的简单使用
添加依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
EventBus 的使用很简单,笼统来说可分为以下几个步骤。
- 创建 EventBus 对象。通常全局或模块内通过单例模式只用一个 EventBus 对象
- 创建消息类
- 创建监听者类
- 注册监听者类。如果有多个 EventBus 对象,监听者类注册在哪个 EventBus 对象下,消息就需要发布到对应的 EventBus
中 - 发布消息
EventBus和AsyncEventBus使用区别
下面的测试案例简单,并且很能说明问题。
EventBus:同步事件总线
1.同步执行,事件发送方在发出事件之后,会等待所有的事件消费方执行完毕后,才会回来继续执行自己后面的代码。
2.事件发送方和事件消费方会在同一个线程中执行,消费方的执行线程取决于发送方。
3.同一个事件的多个订阅者,在接收到事件的顺序上面有不同。谁先注册到Event Bus的,谁先执行,如果是在同一个类中的两个订阅者一起被注册到EventBus的情况,收到事件的顺序跟方法名有关。
AsyncEventBus:异步事件总线
1.异步执行,事件发送方异步发出事件,不会等待事件消费方是否收到,直接执行自己后面的代码。
2.在定义AsyncEventBus时,构造函数中会传入一个线程池。事件消费方收到异步事件时,消费方会从线程池中获取一个新的线程来执行自己的任务。
3.同一个事件的多个订阅者,它们的注册顺序跟接收到事件的顺序上没有任何联系,都会同时收到事件,并且都是在新的线程中,异步并发的执行自己的任务。
同步代码:
EventBus
事件消息:
/**
* @className: MessageEvent
* @author: czh
* @date: 2023/4/21
* @despriction: 事件消息
* @version: 1.0.0
**/
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
事件监听,@Subscribe注解:
/**
* @className: SyncEventListener
* @author: czh
* @date: 2023/4/21
* @despriction: 事件监听,@Subscribe注解
* @version: 1.0.0
**/
public class SyncEventListener {
@Subscribe
public void handleMethod(@NotNull MessageEvent msg) {
System.out.printf("SynchEventListener handleMethod received message: %s \n", msg.getMessage());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.printf("SynchEventListener handleMethod process message: %s \n", msg.getMessage());
}
}
同步eventBus测试:
/**
* @className: TestMain
* @author: czh
* @date: 2023/4/21
* @description: google同步eventBus测试
* @version: 1.0.0
**/
public class TestMain {
public static void main(String[] args) {
System.out.println("step 1------------TestMain main create eventBus Object identifier: eventBus = new EventBus(\"test\") .");
EventBus eventBus = new EventBus("test");
System.out.println("step 2------------TestMain main eventBus new listener: eventListener = new SyncEventListener().");
SyncEventListener eventListener = new SyncEventListener();
System.out.println("step 3------------TestMain main eventBus register event listener: eventBus.register(eventListener).");
eventBus.register(eventListener);
System.out.println("step 4------------TestMain main eventBus post event: eventBus.post(new MessageEvent(\"消息同步发送\" + i))");
for (int i=0; i<5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("-----------------TestMain main eventBus post event message.");
eventBus.post(new MessageEvent("消息同步发送" + i));
}
}
}
执行输出信息:
step 1------------TestMain main create eventBus Object identifier: eventBus = new EventBus("test") .
step 2------------TestMain main eventBus new listener: eventListener = new SyncEventListener().
step 3------------TestMain main eventBus register event listener: eventBus.register(eventListener).
step 4------------TestMain main eventBus post event: eventBus.post(new MessageEvent("消息同步发送" + i))
-----------------TestMain main eventBus post event message.
SynchEventListener handleMethod received message: 消息同步发送0
SynchEventListener handleMethod process message: 消息同步发送0
-----------------TestMain main eventBus post event message.
SynchEventListener handleMethod received message: 消息同步发送1
SynchEventListener handleMethod process message: 消息同步发送1
在上面的代码中,添加了几个 sleep,在实际运行的时候注意输出,所有的事件消息都是顺序输出的。这是因为事件的发送方和事件消费方都在一个线程中,事件发送方只有在发送的事件处理完毕后才会继续执行自己后面的代码。这里可使用
AsyncEventBus 类实现事件的异步处理,也就是将事件处理放到一个线程池里面去执行。
异步代码例子:
AsyncEventBus(EventBus 的异步实现)
Demo1-------------------------------------------------------------------------------------------------------------
事件消息:
/**
* @className: MessageEvent
* @author: czh
* @date: 2023/4/21
* @despriction: 事件消息
* @version: 1.0.0
**/
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
event bus listener:
/**
* @className: AsyncEventListener
* @author: czh
* @date: 2023/4/21
* @description: event bus listener
* @version: 1.0.0
**/
public class AsyncEventListener {
@Subscribe
public void method1( MessageEvent msg) {
System.out.printf("AsyncEventListener method1 Subscribe received message: %s \n", msg.getMessage());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("AsyncEventListener method1 Subscribe process message: %s \n", msg.getMessage());
}
@Subscribe
public void method2( MessageEvent msg) {
System.out.printf("AsyncEventListener method2 Subscribe received message: %s \n", msg.getMessage());
System.out.printf("AsyncEventListener method2 Subscribe process message: %s \n", msg.getMessage());
}
}
异步eventBus测试:
/**
* @className: TestMain
* @author: czh
* @date: 2023/4/21
* @description: google异步eventBus测试
* @version: 1.0.0
**/
public class TestMain {
public static void main(String[] args) throws InterruptedException {
System.out.println("step 1------------TestMain main create executor .");
Executor executor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
System.out.println("step 2------------TestMain main create AsyncEventBus with executor: eventBus = new AsyncEventBus(executor) .");
AsyncEventBus eventBus = new AsyncEventBus(executor);
System.out.println("step 3------------TestMain main create EventListener: listener = new AsyncEventListener() .");
AsyncEventListener listener = new AsyncEventListener();
System.out.println("step 4------------TestMain main eventbus register listener: eventBus.register(listener) .");
eventBus.register(listener);
System.out.println("step 5------------TestMain main eventbus post event: eventBus.post(new MessageEvent(\"异步消息\" + i)); .");
for (int i = 0; i < 10; i++) {
System.out.println("-----------------TestMain main eventBus post event message.");
eventBus.post(new MessageEvent("异步消息" + i));
}
}
}
执行输出信息:
step 1------------TestMain main create executor .
step 2------------TestMain main create AsyncEventBus with executor: eventBus = new AsyncEventBus(executor) .
step 3------------TestMain main create EventListener: listener = new AsyncEventListener() .
step 4------------TestMain main eventbus register listener: eventBus.register(listener) .
step 5------------TestMain main eventbus post event: eventBus.post(new MessageEvent("异步消息" + i)); .
-----------------TestMain main eventBus post event message.
-----------------TestMain main eventBus post event message.
AsyncEventListener method2 Subscribe received message: 异步消息0
AsyncEventListener method2 Subscribe process message: 异步消息0
AsyncEventListener method1 Subscribe received message: 异步消息0
AsyncEventListener method2 Subscribe received message: 异步消息1
AsyncEventListener method2 Subscribe process message: 异步消息1
AsyncEventListener method1 Subscribe process message: 异步消息0
AsyncEventListener method1 Subscribe received message: 异步消息1
AsyncEventListener method1 Subscribe process message: 异步消息1
Demo2-------------------------------------------------------------------------------------------------------------
目录结构介绍:
event:一个自定义的事件类,类的内容随意定义。
eventListeners:定义了两个事件监听者类,类里面的方法加@Subscribe注解。
util:eventBus工具类。
TestMain类,测试函数。
public class CustomEvent {
private int age;
public CustomEvent(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
}
public class MessageEvent {
private String message;
public MessageEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
public class EventListener1 {
@Subscribe
public void test1(CustomEvent event){
System.out.println(Instant.now() +"监听者1-->订阅者1,收到事件:"+event.getAge()+",线程号为:"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Subscribe
public void test2(CustomEvent event){
System.out.println(Instant.now() +"监听者1-->订阅者2,收到事件:"+event.getAge()+",线程号为:"+Thread.currentThread().getName());
}
}
public class MessageEventListener {
@Subscribe
public void method1(Message msg){
System.out.println("method1:接收消息," + msg.getMessage());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("method1:处理消息," + msg.getMessage());
}
@Subscribe
public void method2(MessageEvent msgEvent){
System.out.println("method2:接收消息," + msgEvent.getMessage());
System.out.println("method2:处理消息," + msgEvent.getMessage());
}
}
public class EventListener2 {
@Subscribe
public void test(CustomEvent event){
System.out.println(Instant.now() +",监听者2,收到事件:"+event.getAge()+",线程号为:"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class EventBusUtil {
private static EventBus eventBus;
private static AsyncEventBus asyncEventBus;
private static Executor executor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
//双重锁单例模式
private static AsyncEventBus getAsynEventBus(){
if(asyncEventBus==null){
synchronized (AsyncEventBus.class){
if(asyncEventBus==null){
asyncEventBus = new AsyncEventBus(executor);
}
}
}
return asyncEventBus;
}
//双重锁单例模式
private static EventBus getEventBus(){
if(eventBus==null){
synchronized (EventBus.class){
if(eventBus==null){
eventBus = new EventBus();
}
}
}
return eventBus;
}
public static void post(Object event){
getEventBus().post(event);
}
//异步方式发送事件
public static void asyncPost(Object event){
getAsynEventBus().post(event);
}
public static void register(Object object){
getEventBus().register(object);
getAsynEventBus().register(object);
}
}
public class TestMain {
public static void main(String[] args) {
EventListener1 listener1 = new EventListener1();
EventListener2 listener2 = new EventListener2();
CustomEvent customEvent = new CustomEvent(23);
EventBusUtil.register(listener1);
EventBusUtil.register(listener2);
EventBusUtil.asyncPost(customEvent);
//EventBusUtil.post(customEvent);
System.out.println(Instant.now() +",主线程执行完毕:"+Thread.currentThread().getName());
//为了定位 g_sync_eventbus 不生效原因
//1.message没问题
MessageEvent messageEvent = new MessageEvent("为了定位g_sync_eventbus不生效原因!");
//2.listener 错误修复: Message msg -> MessageEvent msgEvent 修复
MessageEventListener messageEventListener = new MessageEventListener();
EventBusUtil.register(messageEventListener);
EventBusUtil.asyncPost(messageEvent);
}
}
.
.
.
git代码: 代码地址
.
.
.