From 003ff34af14a84775638083a56482258759b7fca Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 8 Oct 2024 22:52:54 +0800 Subject: [PATCH] add event --- .../dromara/hutool/core/lang/event/Event.java | 25 +++++ .../core/lang/event/EventPublisher.java | 40 ++++++++ .../core/lang/event/SimpleEventPublisher.java | 99 +++++++++++++++++++ .../hutool/core/lang/event/SourceEvent.java | 38 +++++++ .../hutool/core/lang/event/Subscriber.java | 59 +++++++++++ .../hutool/core/lang/event/package-info.java | 31 ++++++ .../lang/event/SimpleEventPublisherTest.java | 35 +++++++ 7 files changed, 327 insertions(+) create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Event.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/EventPublisher.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SimpleEventPublisher.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SourceEvent.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Subscriber.java create mode 100644 hutool-core/src/main/java/org/dromara/hutool/core/lang/event/package-info.java create mode 100644 hutool-core/src/test/java/org/dromara/hutool/core/lang/event/SimpleEventPublisherTest.java diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Event.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Event.java new file mode 100644 index 000000000..b8f4beaa9 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Event.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.lang.event; + +/** + * 事件接口,所有事件必须实现此接口 + * + * @author Looly + */ +public interface Event{ +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/EventPublisher.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/EventPublisher.java new file mode 100644 index 000000000..d24423978 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/EventPublisher.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.lang.event; + +/** + * 事件发布者接口,用于发布事件 + * + * @author Looly + */ +public interface EventPublisher { + + /** + * 注册订阅者,订阅者将接收到所有发布者发布的事件 + * + * @param subscriber 订阅者 + * @return this + */ + EventPublisher register(Subscriber subscriber); + + /** + * 发布事件,事件发布者将事件发布给所有订阅者 + * + * @param event 事件对象 + */ + void publish(Event event); +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SimpleEventPublisher.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SimpleEventPublisher.java new file mode 100644 index 000000000..6a9091294 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SimpleEventPublisher.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.lang.event; + +import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.lang.loader.LazyFunLoader; +import org.dromara.hutool.core.lang.loader.Loader; +import org.dromara.hutool.core.thread.ThreadUtil; +import org.dromara.hutool.core.util.ObjUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; + +/** + * 简单的事件发布者实现,基于{@link Subscriber}和{@link Event}实现 + * + * @author looly + * @since 6.0.0 + */ +public class SimpleEventPublisher implements EventPublisher { + + /** + * 创建一个默认的{@code SimpleEventPublisher},默认线程池为{@link ThreadUtil#newExecutor()} + * + * @return {@code SimpleEventPublisher} + */ + public static SimpleEventPublisher of() { + return of(null); + } + + /** + * 创建一个默认的{@code SimpleEventPublisher},默认线程池为{@link ThreadUtil#newExecutor()} + * + * @param subscribers 订阅者列表,也可以传入空列表后调用{@link #register(Subscriber)}添加 + * @return {@code SimpleEventPublisher} + */ + public static SimpleEventPublisher of(final List subscribers) { + return new SimpleEventPublisher(subscribers, null); + } + + private final List subscribers; + private Loader executorServiceLoader; + + /** + * 构造 + * + * @param subscribers 订阅者列表 + * @param executorServiceLoader 线程池加载器,用于异步执行,默认为{@link ThreadUtil#newExecutor()} + */ + public SimpleEventPublisher(final List subscribers, final Loader executorServiceLoader) { + this.subscribers = ObjUtil.defaultIfNull(subscribers, ArrayList::new); + this.executorServiceLoader = ObjUtil.defaultIfNull(executorServiceLoader, LazyFunLoader.of(ThreadUtil::newExecutor)); + } + + /** + * 设置自定义的{@link ExecutorService}线程池,默认为{@link ThreadUtil#newExecutor()} + * + * @param executorService {@link ExecutorService},不能为空 + * @return this + */ + public SimpleEventPublisher setExecutorService(final ExecutorService executorService) { + this.executorServiceLoader = () -> Assert.notNull(executorService); + return this; + } + + @Override + public EventPublisher register(final Subscriber subscriber) { + subscribers.add(subscriber); + Collections.sort(subscribers); + return this; + } + + @Override + public void publish(final Event event) { + for (final Subscriber subscriber : subscribers) { + if (subscriber.async()) { + executorServiceLoader.get().submit(() -> subscriber.update(event)); + } else { + subscriber.update(event); + } + } + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SourceEvent.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SourceEvent.java new file mode 100644 index 000000000..3d9d778b6 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/SourceEvent.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.lang.event; + +import java.util.EventObject; + +/** + * 基于事件源的事件实现 + * + * @author looly + * @since 6.0.0 + */ +public class SourceEvent extends EventObject implements Event { + private static final long serialVersionUID = 1L; + + /** + * 构造 + * + * @param source 事件源 + */ + public SourceEvent(final Object source) { + super(source); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Subscriber.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Subscriber.java new file mode 100644 index 000000000..6929a121b --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/Subscriber.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.dromara.hutool.core.lang.event; + +import org.dromara.hutool.core.comparator.CompareUtil; + +import java.util.EventListener; + +/** + * 订阅者接口 + * + * @author Looly + */ +public interface Subscriber extends EventListener, Comparable { + + /** + * 当事件发生时的操作 + * + * @param event 事件对象,根据不同事件,可选是否执行 + */ + void update(Event event); + + /** + * 获取事件执行顺序,值越小越先执行 + * + * @return 执行顺序 + */ + default int order() { + return 1000; + } + + @Override + default int compareTo(final Subscriber o) { + return CompareUtil.compare(this.order(), o.order()); + } + + /** + * 是否异步执行,默认为false,同步执行 + * + * @return 是否异步执行 + */ + default boolean async() { + return false; + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/package-info.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/package-info.java new file mode 100644 index 000000000..ee5641d19 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/event/package-info.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 Hutool Team and hutool.cn + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * 发布订阅模式封装,发布/订阅是一种消息范式
+ * 消息的发送者(EventPublisher)将事件或消息(Event)广播出去,订阅者(Subscriber)接收到消息后处理。
+ * Hutool中的事件或消息(Event)是一个无方法接口,可以通过实现此接口灵活的定义不同消息类型。
+ * 消息的发送者(EventPublisher)可以通过register方法注册订阅者,调用publish发布消息 + * + *
{@code
+ *           publish                /----->Subscriber
+ *   Event  -------- EventPublisher- ----->Subscriber
+ *                                  \----->Subscriber
+ * }
+ * + * @author Looly + */ +package org.dromara.hutool.core.lang.event; diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/lang/event/SimpleEventPublisherTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/lang/event/SimpleEventPublisherTest.java new file mode 100644 index 000000000..bb8b2aadc --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/lang/event/SimpleEventPublisherTest.java @@ -0,0 +1,35 @@ +package org.dromara.hutool.core.lang.event; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class SimpleEventPublisherTest { + + @Test + void registerTest() { + final SimpleEventPublisher publisher = SimpleEventPublisher.of(); + publisher.register(event -> Assertions.assertEquals("test", ((TestEvent)event).getName())); + + publisher.publish(new TestEvent("test")); + } + + @Test + void sourceEventTest() { + final SimpleEventPublisher publisher = SimpleEventPublisher.of(); + publisher.register(event -> Assertions.assertEquals("test", ((SourceEvent)event).getSource())); + + publisher.publish(new SourceEvent("test")); + } + + private static class TestEvent implements Event { + private final String name; + + public TestEvent(final String name) { + this.name = name; + } + + public String getName() { + return name; + } + } +}