init project

This commit is contained in:
jaysunxiao committed 2021-05-20 14:17:21 +08:00
1 parent b7f28da485
commit bce060a28e
573 files changed
+84513

No files matched your search

+244
View File
@@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zfoo</groupId>
<artifactId>event</artifactId>
<version>3.0</version>
<packaging>jar</packaging>
<properties>
<!-- 本项目的其它module版本号 -->
<zfoo.event.version>3.0</zfoo.event.version>
<zfoo.hotswap.version>3.0</zfoo.hotswap.version>
<zfoo.monitor.version>3.0</zfoo.monitor.version>
<zfoo.net.version>3.0</zfoo.net.version>
<zfoo.scheduler.version>3.0</zfoo.scheduler.version>
<zfoo.storage.version>3.0</zfoo.storage.version>
<zfoo.orm.version>3.0</zfoo.orm.version>
<zfoo.protocol.version>3.0</zfoo.protocol.version>
<zfoo.util.version>3.0</zfoo.util.version>
<!-- 核心spring框架 -->
<spring.version>5.3.4</spring.version>
<spring.boot.version>2.4.3</spring.boot.version>
<!-- 工具包 -->
<commons-codec.version>1.15</commons-codec.version>
<commons-io.version>2.8.0</commons-io.version>
<commons-collections.version>4.4</commons-collections.version>
<commons-lang.version>3.12.0</commons-lang.version>
<commons-fileupload.version>1.4</commons-fileupload.version>
<commons-logging.version>1.2</commons-logging.version>
<commons-log4j.version>2.14.0</commons-log4j.version>
<httpcomponents.version>4.5.13</httpcomponents.version>
<httpcore.version>4.4.14</httpcore.version>
<google.guava.version>30.1-jre</google.guava.version>
<google.protobuf.version>3.9.1</google.protobuf.version>
<google.gson.version>2.8.6</google.gson.version>
<kryo.version>5.0.3</kryo.version>
<caffeine.version>2.8.8</caffeine.version>
<jctools.version>3.2.0</jctools.version>
<hutool.version>5.5.9</hutool.version>
<oshi.version>5.7.0</oshi.version>
<snakeyaml.version>1.28</snakeyaml.version>
<!-- json和xml解析包 -->
<jackson.version>2.12.1</jackson.version>
<fastjson.version>1.2.51</fastjson.version>
<!-- office文档解析包 -->
<poi.version>4.1.2</poi.version>
<!-- 字节码增强 -->
<javassist.version>3.27.0-GA</javassist.version>
<bytebuddy.version>1.10.22</bytebuddy.version>
<!-- 网络通讯框架 -->
<netty.version>4.1.63.Final</netty.version>
<!-- 分布式zookeeper核心依赖包 -->
<zookeeper.version>3.6.1</zookeeper.version>
<curator.version>5.1.0</curator.version>
<!-- 数据库和缓存 -->
<mongodb-driver-sync.version>4.2.1</mongodb-driver-sync.version>
<jedis.version>3.3.0</jedis.version>
<!-- 消息队列中间件 -->
<rocketmq.version>4.5.2</rocketmq.version>
<!-- elastic search 中间件 -->
<elastic.search.version>7.9.3</elastic.search.version>
<elastic.search.spring.version>4.1.5</elastic.search.spring.version>
<lucene.version>8.6.2</lucene.version>
<slf4j.version>1.7.30</slf4j.version>
<logback.version>1.2.3</logback.version>
<junit.version>4.13.1</junit.version>
<!-- java版本和文件编码 -->
<java.version>11</java.version>
<file.encoding>UTF-8</file.encoding>
<jakarta.version>1.3.5</jakarta.version>
<!-- maven核心插件 -->
<maven-clean-plugin.version>3.1.0</maven-clean-plugin.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-resources-plugin.version>3.2.0</maven-resources-plugin.version>
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
<maven-jar-plugin.version>3.2.0</maven-jar-plugin.version>
<maven-shade-plugin.version>3.2.4</maven-shade-plugin.version>
<versions-maven-plugin.version>2.8.1</versions-maven-plugin.version>
<project.build.sourceEncoding>${file.encoding}</project.build.sourceEncoding>
<maven.compiler.encoding>${file.encoding}</maven.compiler.encoding>
</properties>
<dependencies>
<!-- 依赖的utils类库 -->
<dependency>
<groupId>com.zfoo</groupId>
<artifactId>util</artifactId>
<version>${zfoo.util.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
<!-- 动态生成二进制字节码的javassist类库 -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javassist.version}</version>
</dependency>
<!-- 依赖的Spring模块类库 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- logback核心包 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- logback的sl4j的实现 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 依赖的测试库 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<plugins>
<!-- 清理插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
</plugin>
<!-- 编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${file.encoding}</encoding>
</configuration>
</plugin>
<!-- resource资源管理插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<encoding>${file.encoding}</encoding>
<outputDirectory>${project.build.directory}/resource</outputDirectory>
<resources>
<resource>
<directory>src/main/resources/</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- 测试插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkMode>once</forkMode>
<threadCount>10</threadCount>
<argLine>-Dfile.encoding=${file.encoding}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event;
import com.zfoo.event.manager.EventBus;
import com.zfoo.event.schema.EventRegisterProcessor;
import com.zfoo.protocol.exception.ExceptionUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.util.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
/**
* @author jaysunxiao
* @version 3.0
*/
public class EventContext implements ApplicationListener<ApplicationContextEvent>, Ordered {
private static final Logger logger = LoggerFactory.getLogger(EventContext.class);
private static EventContext instance;
private ApplicationContext applicationContext;
public static EventContext getEventContext() {
return instance;
}
public static ApplicationContext getApplicationContext() {
return instance.applicationContext;
}
public synchronized static void shutdown() {
try {
Field field = EventBus.class.getDeclaredField("executors");
ReflectionUtils.makeAccessible(field);
var executors = (ExecutorService[]) ReflectionUtils.getField(field, null);
for (ExecutorService executor : executors) {
ThreadUtils.shutdown(executor);
}
} catch (Throwable e) {
logger.error("Event thread pool failed shutdown: " + ExceptionUtils.getMessage(e));
return;
}
logger.info("Event shutdown gracefully.");
}
@Override
public void onApplicationEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
if (instance != null) {
return;
}
// 初始化上下文
EventContext.instance = this;
instance.applicationContext = event.getApplicationContext();
var beanNames = applicationContext.getBeanDefinitionNames();
var processor = applicationContext.getBean(EventRegisterProcessor.class);
for (var beanName : beanNames) {
processor.postProcessAfterInitialization(applicationContext.getBean(beanName), beanName);
}
} else if (event instanceof ContextClosedEvent) {
shutdown();
ThreadUtils.shutdownForkJoinPool();
}
}
@Override
public int getOrder() {
return 30;
}
}
@@ -0,0 +1,188 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.manager;
import com.zfoo.event.model.anno.EventReceiver;
import com.zfoo.event.model.event.IEvent;
import com.zfoo.event.model.vo.EnhanceUtils;
import com.zfoo.event.model.vo.EventReceiverDefinition;
import com.zfoo.event.model.vo.IEventReceiver;
import com.zfoo.protocol.collection.CollectionUtils;
import com.zfoo.protocol.util.ReflectionUtils;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.util.math.RandomUtils;
import io.netty.util.concurrent.FastThreadLocalThread;
import javassist.CannotCompileException;
import javassist.NotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author jaysunxiao
* @version 3.0
*/
public abstract class EventBus {
private static final Logger logger = LoggerFactory.getLogger(EventBus.class);
// 线程池的大小
private static final int EXECUTORS_SIZE = Runtime.getRuntime().availableProcessors() * 2;
private static final ExecutorService[] executors;
private static final Map<Class<? extends IEvent>, List<IEventReceiver>> receiverMap;
static {
receiverMap = new HashMap<>();
executors = new ExecutorService[EXECUTORS_SIZE];
for (int i = 0; i < executors.length; i++) {
var namedThreadFactory = new EventThreadFactory();
executors[i] = Executors.newSingleThreadExecutor(namedThreadFactory);
}
}
private static class EventThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
EventThreadFactory() {
var s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "event-p" + poolNumber.getAndIncrement() + "-t";
}
@Override
public Thread newThread(Runnable runnable) {
var t = new FastThreadLocalThread(group, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
t.setDaemon(false);
t.setPriority(Thread.NORM_PRIORITY);
t.setUncaughtExceptionHandler((thread, e) -> logger.error(thread.toString(), e));
return t;
}
}
/**
* 同步抛出一个事件,会在当前线程中运行
*
* @param event 需要抛出的事件
*/
public static void syncSubmit(IEvent event) {
var list = receiverMap.get(event.getClass());
if (CollectionUtils.isEmpty(list)) {
return;
}
doSubmit(event, list);
}
/**
* 异步抛出一个事件,事件不在同一个线程中处理
*
* @param event 需要抛出的事件
*/
public static void asyncSubmit(IEvent event) {
var list = receiverMap.get(event.getClass());
if (CollectionUtils.isEmpty(list)) {
return;
}
executors[Math.abs(event.threadId() % EXECUTORS_SIZE)].execute(new Runnable() {
@Override
public void run() {
doSubmit(event, list);
}
});
}
/**
* 随机获取一个线程池
*/
public static Executor asyncExecute() {
return executors[RandomUtils.randomInt(EXECUTORS_SIZE)];
}
private static void doSubmit(IEvent event, List<IEventReceiver> listReceiver) {
for (var receiver : listReceiver) {
try {
receiver.invoke(event);
} catch (Exception e) {
logger.error("eventBus未知exception异常", e);
} catch (Throwable t) {
logger.error("eventBus未知error异常", t);
}
}
}
public static void registerEventReceiver(Object bean) {
try {
var clazz = bean.getClass();
var methods = ReflectionUtils.getMethodsByAnnoInPOJOClass(clazz, EventReceiver.class);
for (var method : methods) {
var paramClazzs = method.getParameterTypes();
if (paramClazzs.length != 1) {
throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] must have one parameter!", bean.getClass().getName(), method.getName()));
}
if (!IEvent.class.isAssignableFrom(paramClazzs[0])) {
throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] must have one [IEvent] type parameter!", bean.getClass().getName(), method.getName()));
}
var eventClazz = (Class<? extends IEvent>) paramClazzs[0];
var eventName = eventClazz.getCanonicalName();
var methodName = method.getName();
if (!Modifier.isPublic(method.getModifiers())) {
throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] [event:{}] must use 'public' as modifier!", bean.getClass().getName(), methodName, eventName));
}
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] [event:{}] can not use 'static' as modifier!", bean.getClass().getName(), methodName, eventName));
}
var expectedMethodName = StringUtils.format("on{}", eventClazz.getSimpleName());
if (!methodName.equals(expectedMethodName)) {
throw new IllegalArgumentException(StringUtils.format("[class:{}] [method:{}] [event:{}] expects '{}' as method name!"
, bean.getClass().getName(), methodName, eventName, expectedMethodName));
}
var receiverDefinition = new EventReceiverDefinition(bean, method, eventClazz);
if (!receiverMap.containsKey(eventClazz)) {
receiverMap.put(eventClazz, new LinkedList<>());
}
var enhanceReceiverDefinition = EnhanceUtils.createEventReceiver(receiverDefinition);
receiverMap.get(eventClazz).add(enhanceReceiverDefinition);
}
} catch (NotFoundException | CannotCompileException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.anno;
import java.lang.annotation.*;
/**
* 接受时间注解
*
* @author jaysunxiao
* @version 3.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface EventReceiver {
}
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.event;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;
/**
* 应用启动事件,这个使用spring自带的事件机制,自研的event事件仅用在业务逻辑
*
* @author jaysunxiao
* @version 3.0
*/
public class AppStartEvent extends ApplicationContextEvent {
public AppStartEvent(ApplicationContext context) {
super(context);
}
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.event;
import com.zfoo.util.math.RandomUtils;
/**
* @author jaysunxiao
* @version 3.0
*/
public interface IEvent {
/**
* 这个返回的是一个用于确定事件在EventBus中的哪个线程池的执行的一个参数,只有异步事件才会有作用
* <p>
* 比如cpu是四核,那么EventBus中的executors线程池的数量为8个,通过取余可以确定异步事件在哪个线程池中执行。
* 如果参数是0,0 % 8 = 0,那么异步事件最终会在executors[0]表示的线程池中执行
* 如果参数是1,1 % 8 = 1,那么异步事件最终会在executors[1]表示的线程池中执行
* 如果参数是8,8 % 8 = 0,那么异步事件最终会在executors[0]表示的线程池中执行
* 如果参数是9,9 % 8 = 1,那么异步事件最终会在executors[1]表示的线程池中执行
* <p>
* 通过返回的参数,可以轻松控制异步事件在哪个线程池中去执行。
* 因为EventBus中的线程池都是单线程线程池,如果将一些异步事件放在同一个线程池中执行,可以不用加锁,提高程序运行的效率。
* <p>
* 默认返回一个随机数,这就导致如果不重写这个方法,那么异步事件有可能会在EventBus中的任何一条线程池中去执行。
*
* @return 线程池的执行的一个参数
*/
default int threadId() {
return RandomUtils.randomInt();
}
}
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.vo;
import com.zfoo.event.model.event.IEvent;
import com.zfoo.event.schema.NamespaceHandler;
import com.zfoo.protocol.util.StringUtils;
import com.zfoo.util.security.IdUtils;
import javassist.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* @author jaysunxiao
* @version 3.0
*/
public abstract class EnhanceUtils {
static {
// 适配Tomcat,因为Tomcat不是用的默认的类加载器,而Javaassist用的是默认的加载器
var classArray = new Class<?>[]{
IEventReceiver.class,
IEvent.class
};
var classPool = ClassPool.getDefault();
for (var clazz : classArray) {
if (classPool.find(clazz.getCanonicalName()) == null) {
ClassClassPath classPath = new ClassClassPath(clazz);
classPool.insertClassPath(classPath);
}
}
}
public static IEventReceiver createEventReceiver(EventReceiverDefinition definition) throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
var classPool = ClassPool.getDefault();
Object bean = definition.getBean();
Method method = definition.getMethod();
Class<?> clazz = definition.getEventClazz();
// 定义类名称
CtClass enhanceClazz = classPool.makeClass(EnhanceUtils.class.getCanonicalName() + StringUtils.capitalize(NamespaceHandler.EVENT) + IdUtils.getLocalIntId());
enhanceClazz.addInterface(classPool.get(IEventReceiver.class.getCanonicalName()));
// 定义类中的一个成员
CtField field = new CtField(classPool.get(bean.getClass().getCanonicalName()), "bean", enhanceClazz);
field.setModifiers(Modifier.PRIVATE);
enhanceClazz.addField(field);
// 定义类的构造器
CtConstructor constructor = new CtConstructor(classPool.get(new String[]{bean.getClass().getCanonicalName()}), enhanceClazz);
constructor.setBody("{this.bean=$1;}");
constructor.setModifiers(Modifier.PUBLIC);
enhanceClazz.addConstructor(constructor);
// 定义类实现的接口方法
CtMethod invokeMethod = new CtMethod(classPool.get(void.class.getCanonicalName()), "invoke", classPool.get(new String[]{IEvent.class.getCanonicalName()}), enhanceClazz);
invokeMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
String invokeMethodBody = "{this.bean." + method.getName() + "((" + clazz.getCanonicalName() + ")$1);}";// 强制类型转换,转换为具体的Event类型的类型
invokeMethod.setBody(invokeMethodBody);
enhanceClazz.addMethod(invokeMethod);
// 释放缓存
enhanceClazz.detach();
Class<?> resultClazz = enhanceClazz.toClass(IEventReceiver.class);
Constructor<?> resultConstructor = resultClazz.getConstructor(bean.getClass());
IEventReceiver receiver = (IEventReceiver) resultConstructor.newInstance(bean);
return receiver;
}
}
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.vo;
import com.zfoo.event.model.event.IEvent;
import com.zfoo.protocol.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
* @author jaysunxiao
* @version 3.0
*/
public class EventReceiverDefinition implements IEventReceiver {
private Object bean;
// 被ReceiveEvent注解的方法
private Method method;
// 接收的参数Class
private Class<? extends IEvent> eventClazz;
public EventReceiverDefinition(Object bean, Method method, Class<? extends IEvent> eventClazz) {
this.bean = bean;
this.method = method;
this.eventClazz = eventClazz;
ReflectionUtils.makeAccessible(this.method);
}
@Override
public void invoke(IEvent event) {
ReflectionUtils.invokeMethod(bean, method, event);
}
public Object getBean() {
return bean;
}
public void setBean(Object bean) {
this.bean = bean;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Class<? extends IEvent> getEventClazz() {
return eventClazz;
}
public void setEventClazz(Class<? extends IEvent> eventClazz) {
this.eventClazz = eventClazz;
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.model.vo;
import com.zfoo.event.model.event.IEvent;
/**
* @author jaysunxiao
* @version 3.0
*/
public interface IEventReceiver {
void invoke(IEvent event);
}
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.schema;
import com.zfoo.event.EventContext;
import com.zfoo.protocol.util.StringUtils;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* @author jaysunxiao
* @version 3.0
*/
public class EventDefinitionParser implements BeanDefinitionParser {
@Override
public AbstractBeanDefinition parse(Element element, ParserContext parserContext) {
Class<?> clazz;
String name;
BeanDefinitionBuilder builder;
// 注册EventSpringContext
clazz = EventContext.class;
name = StringUtils.uncapitalize(clazz.getName());
builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
parserContext.getRegistry().registerBeanDefinition(name, builder.getBeanDefinition());
// 注册EventRegisterProcessor,event事件处理
clazz = EventRegisterProcessor.class;
name = StringUtils.uncapitalize(clazz.getName());
builder = BeanDefinitionBuilder.rootBeanDefinition(clazz);
parserContext.getRegistry().registerBeanDefinition(name, builder.getBeanDefinition());
return builder.getBeanDefinition();
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.schema;
import com.zfoo.event.EventContext;
import com.zfoo.event.manager.EventBus;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author jaysunxiao
* @version 3.0
*/
public class EventRegisterProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (EventContext.getEventContext() == null) {
return bean;
}
EventBus.registerEventReceiver(bean);
return bean;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event.schema;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* @author jaysunxiao
* @version 3.0
*/
public class NamespaceHandler extends NamespaceHandlerSupport {
public static final String EVENT = "event";
@Override
public void init() {
registerBeanDefinitionParser(EVENT, new EventDefinitionParser());
}
}
@@ -0,0 +1 @@
http\://www.zfoo.com/schema/event=com.zfoo.event.schema.NamespaceHandler
@@ -0,0 +1 @@
http\://www.zfoo.com/schema/event-1.0.xsd=event-1.0.xsd
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.zfoo.com/schema/event"
targetNamespace="http://www.zfoo.com/schema/event"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="event">
<xsd:complexType>
<xsd:attribute name="id" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event;
import com.zfoo.event.manager.EventBus;
import com.zfoo.util.ThreadUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author jaysunxiao
* @version 3.0
*/
@Ignore
public class ApplicationTest {
// 事件总线教程
@Test
public void startEventTest() {
// 加载配置文件,配置文件中必须引入event
var context = new ClassPathXmlApplicationContext("application.xml");
// 事件的接受需要在被Spring管理的bean的方法上加上@EventReceiver注解,即可自动注册事件的监听
// 参考MyController1中的标准注册方法
// 抛出同步事件,事件会被当前线程立刻执行,注意日志打印的线程号
EventBus.syncSubmit(MyNoticeEvent.valueOf("同步事件"));
// 抛出异步事件,事件会被不会立刻执行,注意日志打印的线程号
EventBus.asyncSubmit(MyNoticeEvent.valueOf("异步事件"));
// 睡眠3秒,等待异步事件执行完
ThreadUtils.sleep(3000);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event;
import com.zfoo.event.model.anno.EventReceiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @author jaysunxiao
* @version 3.0
*/
@Component
public class MyController1 {
private static final Logger logger = LoggerFactory.getLogger(MyController1.class);
@EventReceiver
public void onMyNoticeEvent(MyNoticeEvent event) {
logger.info("方法1收到事件:" + event.getMessage());
}
}
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event;
import com.zfoo.event.model.anno.EventReceiver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* @author jaysunxiao
* @version 3.0
*/
@Component
public class MyController2 {
private static final Logger logger = LoggerFactory.getLogger(MyController2.class);
/**
* 同一个事件可以被重复注册和接受
*/
@EventReceiver
public void onMyNoticeEvent(MyNoticeEvent event) {
logger.info("方法2收到事件:" + event.getMessage());
}
}
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 The zfoo Authors
*
* 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 com.zfoo.event;
import com.zfoo.event.model.event.IEvent;
/**
* @author jaysunxiao
* @version 3.0
*/
public class MyNoticeEvent implements IEvent {
private String message;
public static MyNoticeEvent valueOf(String message) {
var event = new MyNoticeEvent();
event.setMessage(message);
return event;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
+23
View File
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:event="http://www.zfoo.com/schema/event"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.zfoo.com/schema/event
http://www.zfoo.com/schema/event-1.0.xsd">
<context:component-scan base-package="com.zfoo.event"/>
<event:event id="eventBus"/>
</beans>
+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" debug="false">
<contextName>com.zfoo.event</contextName>
<property name="LOG_HOME" value="log/event"/>
<property name="PATTERN_FILE"
value="%d{yyyy-MM-dd HH:mm:ss} [%5level] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
<property name="PATTERN_CONSOLE"
value="%d{yyyy-MM-dd HH:mm:ss} [%highlight(%5level)] [%thread] %logger.%M\\(%F:%line\\) - %msg%n"/>
<!-- 负责写日志,控制台日志,会打印所有的包的所有级别日志 -->
<appender name="zfoo_console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN_CONSOLE}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 根logger -->
<root level="info">
<appender-ref ref="zfoo_console"/>
</root>
<!--
- 1.name:包名或类名,用来指定受此logger约束的某一个包或者具体的某一个类
- 2.未设置打印级别,所以继承他的上级<root>的日志级别“DEBUG”
- 3.未设置additivity,默认为true,将此logger的打印信息向上级传递;
- 4.未设置appender,此logger本身不打印任何信息,级别为“DEBUG”及大于“DEBUG”的日志信息传递给root,
- root接到下级传递的信息,交给已经配置好的名为“STDOUT”的appender处理,“STDOUT”appender将信息打印到控制台;
-->
<logger name="ch.qos.logback" level="info"/>
<!--*******************************************Spring********************************************************-->
<!--logger中的name是指代码的包名或类名,路径要写全,可以配置不同包中的日志输出到不同的文件中。level是日志输出级别 -->
<!--过滤掉spring的一些无用的DEBUG信息-->
<logger name="org.springframework" level="info"/>
<!-- additivity="false"表示不继承父logger的配置和父类没有关系-->
<logger name="org.springframework.core" level="info"/>
<!--*******************************************Netty*********************************************************-->
<logger name="io.netty" level="info"/>
</configuration>
Binary file not shown.

After

Width:  |  Height:  |  Size: 992 KiB