十、guava eventbus

EventBus 是 Guava 的事件处理机制,是观察者模式(生产/消费模型)的一种实现。根据发送对象的类型,查找所有匹配的订阅处理器进行处理。

1. 事件默认在当前线程直接调用处理

1.1.简单使用示例

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

public class EventBusTest {
    @AllArgsConstructor
    @Data
    public static class Person {
        private String name;
        private int age;
    }

    public static class SimpleListener {
        @Subscribe
        // Subscribe注解标注的方法为订阅处理器,处理String类型的事件
        public void doSomething(String event) {
            System.out.println(this.getClass().getSimpleName() + ":" + event);
        }

        @Subscribe
        public void doSomething2(String event) {
            System.out.println(this.getClass().getSimpleName() + "2:" + event);
        }

        @Subscribe
        // 订阅处理Person类型的事件
        public void personListener(Person person) {
            System.out.println(this.getClass().getSimpleName() + ":" + person);
        }
    }

    @Test
    public void test() {
        EventBus eventBus = new EventBus();

        // 注解监听者
        eventBus.register(new SimpleListener());

        // 发送事件
        eventBus.post("发送字符串!");
        eventBus.post(new Person("张三", 20));
    }
}

执行结果:

SimpleListener2:发送字符串!
SimpleListener:发送字符串!
SimpleListener:EventBusTest.Person(name=张三, age=20)

1.2 监听器有继承关系时

    监听器有继承关系时,父类和子类所有被Subscribe注解标记的方法都会被注册为事件订阅处理器。

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

public class EventBusTest {
    @AllArgsConstructor
    @Data
    public static class Person {
        private String name;
        private int age;
    }

    public static abstract class absListener {
        @Subscribe
        public void doSomething2(String event) {
            System.out.println(this.getClass().getSimpleName() + "2:" + event);
        }

        @Subscribe
        public void personListener(Person person) {
            System.out.println(this.getClass().getSimpleName() + ":" + person);
        }

    }

    public static class SimpleListener extends absListener {
        @Subscribe
        public void doSomething(String event) {
            System.out.println(this.getClass().getSimpleName() + ":" + event);
        }
    }

    @Test
    public void test() {
        EventBus eventBus = new EventBus();
        eventBus.register(new SimpleListener());
        eventBus.post("发送字符串!");
        eventBus.post(new Person("张三", 20));
    }
}

执行结果:

SimpleListener:发送字符串!
SimpleListener2:发送字符串!
SimpleListener:EventBusTest.Person(name=张三, age=20)

1.3 事件对象有继承关系时

    事件对象有继承关系时,由于子类型可以转换为父类型,订阅父类型的处理器可以订阅到子类型进行处理:

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.SuperBuilder;
import org.junit.Test;

public class EventBusTest {
    @AllArgsConstructor
    @SuperBuilder
    @Data
    public static class Person {
        private String name;
        private int age;
    }

    @SuperBuilder()
    public static class Man extends Person {
    }

    public static class SimpleListener {
        @Subscribe
        public void personListener(Person person) {
            System.out.println(this.getClass().getSimpleName() + "---Person:" + person);
        }

        @Subscribe
        public void manListener(Man man) {
            System.out.println(this.getClass().getSimpleName() + "---Man:" + man);
        }
    }

    @Test
    public void test() {
        EventBus eventBus = new EventBus();
        eventBus.register(new SimpleListener());
        eventBus.post(Man.builder().name("张三").age(20).build());
    }
}

执行结果:

SimpleListener---Man:EventBusTest.Person(name=张三, age=20)
SimpleListener---Person:EventBusTest.Person(name=张三, age=20)

1.4 订阅处理器执行异常不会影响其他订阅处理器执行

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.junit.Test;

public class EventBusTest {
    public static class SimpleListener {
        @Subscribe
        public void listener1(String event) {
            System.out.println(this.getClass().getSimpleName() + "---1111:" + event);
            throw new RuntimeException();
        }

        @Subscribe
        public void listener2(String event) {
            System.out.println(this.getClass().getSimpleName() + "---2222:" + event);
        }
    }

    @Test
    public void test() {
        EventBus eventBus = new EventBus();
        eventBus.register(new SimpleListener());
        eventBus.post("异常测试");
    }
}

执行结果:

 listener1异常并没有影响listener2的执行。

1.5 自定义异常处理

   在创建EventBus时,可以传入自定义的异常处理方法:

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.junit.Test;

public class EventBusTest {
    public static class SimpleListener {
        @Subscribe
        public void listener1(String event) {
            System.out.println(this.getClass().getSimpleName() + "---1111:" + event);
            throw new RuntimeException();
        }

        @Subscribe
        public void listener2(String event) {
            System.out.println(this.getClass().getSimpleName() + "---2222:" + event);
        }
    }

    @Test
    public void test() {
        // 创建eventbus时,自定义异常处理方法
        EventBus eventBus = new EventBus((exception, context) ->
        {
            // 异常时,可以从context获取eventbus, event,监听器和监听器中发送异常的的事件订阅方法
            System.out.println("ExceptionHandler EventBus:" + context.getEventBus());
            System.out.println("ExceptionHandler Event:" + context.getEvent());
            System.out.println("ExceptionHandler Subscriber:" + context.getSubscriber());
            System.out.println("ExceptionHandler SubscriberMethod:" + context.getSubscriberMethod());
        });
        eventBus.register(new SimpleListener());
        eventBus.post("异常测试");
    }
}

1.6 DeadEvent处理没有订阅的事件

package org.example.model.guava;

import com.google.common.eventbus.DeadEvent;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.junit.Test;

public class EventBusTest {
    public static class SimpleListener {
        @Subscribe
        // 匹配不到任何事件订阅,会使用DeadEvent处理
        public void listener1(DeadEvent event) {
            System.out.println(this.getClass().getSimpleName() + ":" + event);
        }
    }

    @Test
    public void test() {
        EventBus eventBus = new EventBus();
        eventBus.register(new SimpleListener());
        eventBus.post("没有被订阅的消息");
    }
}

1.7 使用eventbus和nio监听文件变化的示例

package org.example.model.guava;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.junit.Test;

import java.io.IOException;
import java.nio.file.*;
import java.util.Optional;


public class EventBusTest {
    @SneakyThrows
    @Test
    public void test() {
        // 创建eventbus时,自定义异常处理方法
        EventBus eventBus = new EventBus();
        eventBus.register(new FileChangeListener());
        DirectoryMonitor monitor = new DirectoryMonitor(eventBus, "D:\\java\\test1\\apache1");
        monitor.start();
    }

    @RequiredArgsConstructor
    public static class DirectoryMonitor {
        private final EventBus eventBus;
        private final String path;
        private WatchService watchService;
        private volatile boolean start;

        public void start() throws IOException {
            watchService = FileSystems.getDefault().newWatchService();
            Path monitorPath = Paths.get(path);
            monitorPath.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                    StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
            start = true;
            WatchKey watchKey = null;
            while (start) {
                try {
                    watchKey = watchService.take();
                    watchKey.pollEvents().forEach(eventBus::post);
                } catch (InterruptedException e) {
                } finally {
                    Optional.ofNullable(watchKey).ifPresent(WatchKey::reset);
                }
            }
        }

        public void stop() throws IOException {
            start = false;
            Thread.currentThread().interrupt();
            watchService.close();
        }
    }

    public static class FileChangeListener {
        @Subscribe
        public void onChange(WatchEvent<?> event) {
            System.out.println(event.context() + "--" + event.kind());
        }
    }
}

在目录 D:\java\test1\apache1 下创建/修改/删除 1.txt,控制台打印如下:

1.txt--ENTRY_CREATE
1.txt--ENTRY_MODIFY
1.txt--ENTRY_DELETE

2. 使用线程池异步处理事件

2.1 使用AsyncEventBus发送异步事件

AsyncEventBus创建时,需要传入使用的线程池:

package org.example.model.guava;

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import lombok.SneakyThrows;
import org.junit.Test;

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class EventBusTest {
    @SneakyThrows
    @Test
    public void test() {
        // 异步事件处理需要提供线程池
        EventBus eventBus = new AsyncEventBus(Executors.newFixedThreadPool(2));
        eventBus.register(new SimpleListener());
        eventBus.post("需要异步处理的事件");

        // 延迟4秒,等待事件处理结束
        TimeUnit.SECONDS.sleep(4);
    }

    public static class SimpleListener {
        @SneakyThrows
        @Subscribe
        public void listener1(String event) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "--listener1 start: " + event);
            TimeUnit.SECONDS.sleep(3);
            System.out.println(threadName + "--listener1 end: " + event);
        }

        @SneakyThrows
        @Subscribe
        public void listener2(String event) {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName + "--listener2 start: " + event);
            TimeUnit.SECONDS.sleep(2);
            System.out.println(threadName + "--listener2 end: " + event);
        }
    }
}

listener1和listener2会使用不同的线程处理,打印结果如下:

pool-1-thread-1--listener2 start: 需要异步处理的事件
pool-1-thread-2--listener1 start: 需要异步处理的事件
pool-1-thread-1--listener2 end: 需要异步处理的事件
pool-1-thread-2--listener1 end: 需要异步处理的事件

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值