add event

This commit is contained in:
Looly
2024-10-08 22:52:54 +08:00
parent 008e21f8f8
commit 003ff34af1
7 changed files with 327 additions and 0 deletions

View File

@@ -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{
}

View File

@@ -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);
}

View File

@@ -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<Subscriber> subscribers) {
return new SimpleEventPublisher(subscribers, null);
}
private final List<Subscriber> subscribers;
private Loader<ExecutorService> executorServiceLoader;
/**
* 构造
*
* @param subscribers 订阅者列表
* @param executorServiceLoader 线程池加载器,用于异步执行,默认为{@link ThreadUtil#newExecutor()}
*/
public SimpleEventPublisher(final List<Subscriber> subscribers, final Loader<ExecutorService> 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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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<Subscriber> {
/**
* 当事件发生时的操作
*
* @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;
}
}

View File

@@ -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.
*/
/**
* 发布订阅模式封装,发布/订阅是一种消息范式<br>
* 消息的发送者EventPublisher将事件或消息Event广播出去订阅者Subscriber接收到消息后处理。<br>
* Hutool中的事件或消息Event是一个无方法接口可以通过实现此接口灵活的定义不同消息类型。<br>
* 消息的发送者EventPublisher可以通过register方法注册订阅者调用publish发布消息
*
* <pre>{@code
* publish /----->Subscriber
* Event -------- EventPublisher- ----->Subscriber
* \----->Subscriber
* }</pre>
*
* @author Looly
*/
package org.dromara.hutool.core.lang.event;

View File

@@ -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;
}
}
}