perf[net]: Wrong configuration gives appropriate hints

This commit is contained in:
godotg
2022-12-11 17:04:07 +08:00
parent 8fadd4b554
commit 8670fea807
21 changed files with 106 additions and 138 deletions
@@ -20,18 +20,18 @@ import com.zfoo.net.session.model.Session;
import com.zfoo.protocol.IPacket;
import org.springframework.lang.Nullable;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public interface IRouter {
/**
* EN:send() and receive() are the entry points for sending and receiving messages, which can be called directly
* CN:send()和receive()是消息的发送和接收的入口,可以直接调用
*/
void send(Session session, IPacket packet);
/**
* send()和receive()是消息的发送和接收的入口,可以直接调用,是最轻量级发送和接收方式
*/
void send(Session session, IPacket packet, @Nullable IAttachment attachment);
void receive(Session session, IPacket packet, @Nullable IAttachment attachment);
@@ -51,9 +51,9 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* 消息派发
* Message distribution
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class Router implements IRouter {
@@ -69,13 +69,8 @@ public class Router implements IRouter {
*/
private final FastThreadLocal<SignalAttachment> serverReceiveSignalAttachmentThreadLocal = new FastThreadLocal<>();
/**
* 在服务端收到数据后,会调用这个方法. 这个方法在BaseRouteHandler.java的channelRead中被调用
*
* @param session
* @param packet
* @param attachment
*/
@Override
public void receive(Session session, IPacket packet, @Nullable IAttachment attachment) {
@@ -234,13 +229,6 @@ public class Router implements IRouter {
* 注意:
* 1.这个里面其实还是调用send发送的消息
* 2.这个argument的参数,只用于provider处哪个线程执行,其实就是hashId,如:工会业务,则传入guildId,回调回来后,一定会在发起者线程。
*
* @param session
* @param packet
* @param answerClass
* @param argument
* @param <T>
* @return
*/
@Override
public <T extends IPacket> AsyncAnswer<T> asyncAsk(Session session, IPacket packet, @Nullable Class<T> answerClass, @Nullable Object argument) {
@@ -344,7 +332,7 @@ public class Router implements IRouter {
// 调用PacketReceiver,进行真正的业务处理,这个submit只是根据packet找到protocolId,然后进行反射调用
// 这个在哪个线程处理取决于:这个上层的PacketReceiverTask被丢到了哪个线程中
PacketBus.submit(session, packet, attachment);
PacketBus.route(session, packet, attachment);
} catch (Exception e) {
EventBus.submit(ServerExceptionEvent.valueOf(session, packet, attachment, e));
logger.error(StringUtils.format("e[uid:{}][sid:{}]未知exception异常", session.getAttribute(AttributeType.UID), session.getSid(), e.getMessage()), e);
@@ -27,12 +27,14 @@ public interface IAsyncAnswer<T extends IPacket> {
IAsyncAnswer<T> thenAccept(Consumer<T> consumer);
/**
* 接收到异步返回的消息,并处理这个消息,异步请求必须要调用这个方法
* EN:To receive the message returned asynchronously and process the message, the asynchronous request must call this method
* CN:接收到异步返回的消息,并处理这个消息,异步请求必须要调用这个方法
*/
void whenComplete(Consumer<T> consumer);
/**
* 没有执行成功的回调的方法
* EN:If the asynchronous request does not return successfully, the method is called
* CN:如果异步请求没有成功返回,那么就会回调该方法
*/
IAsyncAnswer<T> notComplete(SafeRunnable notCompleteCallback);
@@ -17,18 +17,18 @@ import com.zfoo.net.router.attachment.SignalAttachment;
import com.zfoo.protocol.IPacket;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public interface ISyncAnswer<T extends IPacket> {
/**
* @return 请求的返回包
* The return packet for the synchronization request
*/
T packet();
/**
* @return 同步和异步控制的附加包
* attachment for synchronous and asynchronous request
*/
SignalAttachment attachment();
@@ -17,7 +17,7 @@ import com.zfoo.net.router.attachment.SignalAttachment;
import com.zfoo.protocol.IPacket;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class SyncAnswer<T extends IPacket> implements ISyncAnswer<T> {
@@ -16,34 +16,34 @@ import java.util.HashMap;
import java.util.Map;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public enum AttachmentType {
/**
* 带有同步或者异步信息的附加包
* synchronous or asynchronous attachment
*/
SIGNAL_PACKET((byte) 0, SignalAttachment.class),
/**
* 带有网关信息的附加包
* gateway attachment
*/
GATEWAY_PACKET((byte) 1, GatewayAttachment.class),
/**
* udp消息的附加包
* udp attachment
*/
UDP_PACKET((byte) 2, UdpAttachment.class),
/**
* http消息的附加包
* http attachment
*/
HTTP_PACKET((byte) 3, HttpAttachment.class),
/**
* 无返回消息的附加包
* not used attachment
*/
NO_ANSWER_PACKET((byte) 4, NoAnswerAttachment.class),
@@ -18,9 +18,7 @@ import com.zfoo.util.math.HashUtils;
import org.springframework.lang.Nullable;
/**
* 附加包对业务层透明,禁止在业务层使用
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class GatewayAttachment implements IAttachment {
@@ -28,32 +26,34 @@ public class GatewayAttachment implements IAttachment {
public static final transient short PROTOCOL_ID = 1;
/**
* session的id,一般是客户端连接网关的那个sid
* session id
*/
private long sid;
/**
* 用戶Id,从网关转发到后面的消息必须要附带用户的Id信息,要不然无法知道是哪个用户发过来的,0代表没有用户id
* EN:User ID, the message forwarded from the gateway to the back must be accompanied by the user's ID information,
* otherwise it is impossible to know which user sent it, 0 means no user ID
* <p>
* CN:用戶Id,从网关转发到后面的消息必须要附带用户的Id信息,要不然无法知道是哪个用户发过来的,0代表没有用户id
*/
private long uid;
/**
* 是否使用consistentHashId作为一致性hashId
* EN:Whether to use a consistent hash ID as a consistent hash ID
* CN:是否使用consistentHashId作为一致性hashId
*/
private boolean useExecutorConsistentHash;
/**
* 用来在TaskBus中计算一致性hash的参数
*/
private int executorConsistentHash;
/**
* true为客户端,false为服务端
* true for the client, false for the server
*/
private boolean client;
/**
* 客户端发到网关的可能是一个带有同步或者异步的附加包,网关转发的时候需要把这个附加包给带上
* EN:The client may send an packet with synchronous or asynchronous to the gateway, and the gateway needs to bring this attachment when forwarding
* CN:客户端发到网关的可能是一个带有同步或者异步的附加包,网关转发的时候需要把这个附加包给带上
*/
private SignalAttachment signalAttachment;
@@ -17,7 +17,7 @@ import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class HttpAttachment implements IAttachment {
@@ -15,7 +15,7 @@ package com.zfoo.net.router.attachment;
import com.zfoo.protocol.IPacket;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public interface IAttachment extends IPacket {
@@ -23,7 +23,8 @@ public interface IAttachment extends IPacket {
AttachmentType packetType();
/**
* 用来确定这条消息在哪一个线程处理
* EN:Used to determine which thread the message is processed on
* CN:用来确定这条消息在哪一个线程处理
*
* @return 一致性hashId
*/
@@ -13,18 +13,15 @@
package com.zfoo.net.router.attachment;
/**
* 附加包对业务层透明,禁止在业务层使用
* not used attachment
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class NoAnswerAttachment implements IAttachment {
public static final transient short PROTOCOL_ID = 4;
/**
* 用来在TaskBus中计算一致性hash的参数
*/
private int executorConsistentHash;
public static NoAnswerAttachment valueOf(int executorConsistentHash) {
@@ -19,9 +19,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 附加包对业务层透明,禁止在业务层使用
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class SignalAttachment implements IAttachment {
@@ -31,27 +29,30 @@ public class SignalAttachment implements IAttachment {
public static final AtomicInteger ATOMIC_ID = new AtomicInteger(0);
/**
* 唯一标识一个packet, 唯一表示一个Attachmenthashcode() and equals() 也通过signalId计算
* EN:Unique identification of a packet, unique representation of an attachment, hashcode() and equals() equals signalId value
* CN:唯一标识一个packet 唯一表示一个Attachmenthashcode() and equals() 等于signalId
*/
private int signalId = ATOMIC_ID.incrementAndGet();
/**
* 用来在TaskBus中计算一致性hash的参数
* EN:The parameter used to calculate the consistency hash in Task Bus
* CN:用来在TaskBus中计算一致性hash的参数
*/
private int executorConsistentHash = -1;
/**
* true为客户端,false为服务端
* true for the client, false for the server
*/
private boolean client = true;
/**
* 客户端发送的时间
* The time the client sent it
*/
private transient long timestamp = TimeUtils.now();
/**
* 客户端收到服务器回复的时候回调的方法
* EN:The method of callback when the client receives a reply from the server
* CN:客户端收到服务器回复的时候回调的方法
*/
private transient CompletableFuture<IPacket> responseFuture = new CompletableFuture<>();
@@ -15,7 +15,7 @@ package com.zfoo.net.router.attachment;
import com.zfoo.util.math.RandomUtils;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class UdpAttachment implements IAttachment {
@@ -16,7 +16,7 @@ package com.zfoo.net.router.exception;
import com.zfoo.net.packet.common.Error;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class ErrorResponseException extends RuntimeException {
@@ -14,7 +14,7 @@
package com.zfoo.net.router.exception;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class NetTimeOutException extends RuntimeException {
@@ -16,7 +16,7 @@ package com.zfoo.net.router.exception;
import com.zfoo.protocol.exception.RunException;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class UnexpectedProtocolException extends RunException {
@@ -20,13 +20,11 @@ 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
* @author godotg
* @version 3.0
*/
public abstract class EnhanceUtils {
@@ -51,32 +49,27 @@ public abstract class EnhanceUtils {
public static IPacketReceiver createPacketReceiver(PacketReceiverDefinition definition) throws NotFoundException, CannotCompileException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
var classPool = ClassPool.getDefault();
var bean = definition.getBean();
var method = definition.getMethod();
var packetClazz = definition.getPacketClazz();
var attachmentClazz = definition.getAttachmentClazz();
Object bean = definition.getBean();
Method method = definition.getMethod();
Class<?> packetClazz = definition.getPacketClazz();
Class<?> attachmentClazz = definition.getAttachmentClazz();
// 定义类名称
CtClass enhanceClazz = classPool.makeClass(EnhanceUtils.class.getCanonicalName() + "Dispatcher" + IdUtils.getLocalIntId());
var enhanceClazz = classPool.makeClass(EnhanceUtils.class.getCanonicalName() + "Dispatcher" + IdUtils.getLocalIntId());
enhanceClazz.addInterface(classPool.get(IPacketReceiver.class.getCanonicalName()));
// 定义类中的一个成员
CtField field = new CtField(classPool.get(bean.getClass().getCanonicalName()), "bean", enhanceClazz);
var 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);
var 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[]{Session.class.getCanonicalName(), IPacket.class.getCanonicalName(), IAttachment.class.getCanonicalName()}), enhanceClazz);
var invokeMethod = new CtMethod(classPool.get(void.class.getCanonicalName()), "invoke", classPool.get(new String[]{Session.class.getCanonicalName(), IPacket.class.getCanonicalName(), IAttachment.class.getCanonicalName()}), enhanceClazz);
invokeMethod.setModifiers(Modifier.PUBLIC + Modifier.FINAL);
if (attachmentClazz == null) {
// 强制类型转换
// Cast type(强制类型转换)
String invokeMethodBody = StringUtils.format("{this.bean.{}($1, ({})$2);}", method.getName(), packetClazz.getCanonicalName());
invokeMethod.setBody(invokeMethodBody);
} else {
@@ -85,12 +78,11 @@ public abstract class EnhanceUtils {
}
enhanceClazz.addMethod(invokeMethod);
// 释放缓存
enhanceClazz.detach();
Class<?> resultClazz = enhanceClazz.toClass(IPacketReceiver.class);
Constructor<?> resultConstructor = resultClazz.getConstructor(bean.getClass());
IPacketReceiver receiver = (IPacketReceiver) resultConstructor.newInstance(bean);
var resultClazz = enhanceClazz.toClass(IPacketReceiver.class);
var resultConstructor = resultClazz.getConstructor(bean.getClass());
var receiver = (IPacketReceiver) resultConstructor.newInstance(bean);
return receiver;
}
}
@@ -18,7 +18,7 @@ import com.zfoo.net.session.model.Session;
import com.zfoo.protocol.IPacket;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public interface IPacketReceiver {
@@ -16,7 +16,7 @@ package com.zfoo.net.router.receiver;
import java.lang.annotation.*;
/**
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
@Documented
@@ -21,30 +21,31 @@ import com.zfoo.protocol.util.ReflectionUtils;
import java.lang.reflect.Method;
/**
* 动态代理被PacketReceiver注解标注的方法,为了避免反射最终会用javassist字节码增强的方法去代理PacketReceiverDefinition
* EN:Dynamic proxy methods annotated by PacketReceiver annotations, to avoid reflection, will eventually use javassist bytecode enhanced methods to proxy this class
* CN:动态代理被PacketReceiver注解标注的方法,为了避免反射最终会用javassist字节码增强的方法去代理PacketReceiverDefinition
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class PacketReceiverDefinition implements IPacketReceiver {
/**
* 一个controllerbean
* A controller bean
*/
private Object bean;
/**
* 被PacketReceiver注解标注的方法,接受的方法public void atTcpHelloRequest(Session session, TcpHelloRequest request)
* Methods annotated by PacketReceiver annotations, eg: public void atTcpHelloRequest(Session session, TcpHelloRequest request)
*/
private Method method;
/**
* 接收的包的Class类,如TcpHelloRequest
* The protocol class that receives the package, eg: TcpHelloRequest
*/
private Class<?> packetClazz;
/**
* 接收的包的附加包的Class类,如GatewayAttachment
* attachment class, eg: GatewayAttachment
*/
private Class<?> attachmentClazz;
@@ -37,9 +37,10 @@ import org.slf4j.LoggerFactory;
import java.lang.reflect.Modifier;
/**
* 包的接收路线,服务器收到packet调用对应的Receiver
* EN:The receiving route of the packet, the server/client receives the packet and then call corresponding to the Receiver
* CN:包的接收路线,服务器收到packet然后调用对应的Receiver
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public abstract class PacketBus {
@@ -47,19 +48,13 @@ public abstract class PacketBus {
private static final Logger logger = LoggerFactory.getLogger(PacketBus.class);
/**
* 正常消息的接收
* <p>
* 发送者同时能发送多个包
* 接收者同时只能处理一个session的一个包,同一个发送者发送过来的包排队处理
* The routing of the message
*/
public static void submit(Session session, IPacket packet, IAttachment attachment) {
// 客户端和服务端都有接受packet的方法,packetReceiverList对应的就是包的接收方法,将receiver注册到IProtocolRegistration
public static void route(Session session, IPacket packet, IAttachment attachment) {
var packetReceiver = (IPacketReceiver) ProtocolManager.getProtocol(packet.protocolId()).receiver();
if (packetReceiver == null) {
throw new RuntimeException(StringUtils.format("no any packetReceiverDefinition found for this [packet:{}]", packet.getClass().getName()));
}
// 调用PacketReceiver
packetReceiver.invoke(session, packet, attachment);
}
@@ -73,58 +68,52 @@ public abstract class PacketBus {
}
if (!ReflectionUtils.isPojoClass(clazz)) {
logger.warn("消息注册类[{}]不是POJO类,父类的消息接收不会被扫描到", clazz);
logger.warn("The message registration class [{}] is not a POJO class, and the parent class will not be scanned", clazz);
}
for (var method : methods) {
var paramClazzs = method.getParameterTypes();
AssertionUtils.isTrue(paramClazzs.length == 2 || paramClazzs.length == 3
, "[class:{}] [method:{}] must have two or three parameter!", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(paramClazzs.length == 2 || paramClazzs.length == 3, "[class:{}] [method:{}] must have two or three parameter!", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(Session.class.isAssignableFrom(paramClazzs[0])
, "[class:{}] [method:{}],the first parameter must be Session type parameter Exception.", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(Session.class.isAssignableFrom(paramClazzs[0]), "[class:{}] [method:{}],the first parameter must be Session type parameter Exception.", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(IPacket.class.isAssignableFrom(paramClazzs[1])
, "[class:{}] [method:{}],the second parameter must be IPacket type parameter Exception.", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(IPacket.class.isAssignableFrom(paramClazzs[1]), "[class:{}] [method:{}],the second parameter must be IPacket type parameter Exception.", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(paramClazzs.length != 3 || IAttachment.class.isAssignableFrom(paramClazzs[2])
, "[class:{}] [method:{}],the third parameter must be IAttachment type parameter Exception.", bean.getClass().getName(), method.getName());
AssertionUtils.isTrue(paramClazzs.length != 3 || IAttachment.class.isAssignableFrom(paramClazzs[2]), "[class:{}] [method:{}],the third parameter must be IAttachment type parameter Exception.", bean.getClass().getName(), method.getName());
var packetClazz = (Class<? extends IEvent>) paramClazzs[1];
var attachmentClazz = paramClazzs.length == 3 ? paramClazzs[2] : null;
var packetName = packetClazz.getCanonicalName();
var methodName = method.getName();
AssertionUtils.isTrue(Modifier.isPublic(method.getModifiers())
, "[class:{}] [method:{}] [packet:{}] must use 'public' as modifier!", bean.getClass().getName(), methodName, packetName);
AssertionUtils.isTrue(Modifier.isPublic(method.getModifiers()), "[class:{}] [method:{}] [packet:{}] must use 'public' as modifier!", bean.getClass().getName(), methodName, packetName);
AssertionUtils.isTrue(!Modifier.isStatic(method.getModifiers())
, "[class:{}] [method:{}] [packet:{}] can not use 'static' as modifier!", bean.getClass().getName(), methodName, packetName);
AssertionUtils.isTrue(!Modifier.isStatic(method.getModifiers()), "[class:{}] [method:{}] [packet:{}] can not use 'static' as modifier!", bean.getClass().getName(), methodName, packetName);
var expectedMethodName = StringUtils.format("at{}", packetClazz.getSimpleName());
AssertionUtils.isTrue(methodName.equals(expectedMethodName)
, "[class:{}] [method:{}] [packet:{}] expects '{}' as method name!", bean.getClass().getName(), methodName, packetName, expectedMethodName);
AssertionUtils.isTrue(methodName.equals(expectedMethodName), "[class:{}] [method:{}] [packet:{}] expects '{}' as method name!", bean.getClass().getName(), methodName, packetName, expectedMethodName);
// 如果以Request结尾的请求,那么attachment应该为GatewayAttachment
// 如果以Ask结尾的请求,那么attachment不能为GatewayAttachment
// If the request class name ends with Request, then the attachment should be a Gateway Attachment
// If the request class name ends with Ask, then attachment cannot be a Gateway Attachment
if (attachmentClazz != null) {
if (packetName.endsWith(PacketService.NET_REQUEST_SUFFIX)) {
AssertionUtils.isTrue(attachmentClazz.equals(GatewayAttachment.class) || attachmentClazz.equals(UdpAttachment.class) || attachmentClazz.equals(HttpAttachment.class)
, "[class:{}] [method:{}] [packet:{}] must use [attachment:{}]!", bean.getClass().getName(), methodName, packetName, GatewayAttachment.class.getCanonicalName());
AssertionUtils.isTrue(attachmentClazz.equals(GatewayAttachment.class) || attachmentClazz.equals(UdpAttachment.class) || attachmentClazz.equals(HttpAttachment.class), "[class:{}] [method:{}] [packet:{}] must use [attachment:{}]!", bean.getClass().getName(), methodName, packetName, GatewayAttachment.class.getCanonicalName());
} else if (packetName.endsWith(PacketService.NET_ASK_SUFFIX)) {
AssertionUtils.isTrue(!attachmentClazz.equals(GatewayAttachment.class)
, "[class:{}] [method:{}] [packet:{}] can not match with [attachment:{}]!", bean.getClass().getName(), methodName, packetName, GatewayAttachment.class.getCanonicalName());
AssertionUtils.isTrue(!attachmentClazz.equals(GatewayAttachment.class), "[class:{}] [method:{}] [packet:{}] can not match with [attachment:{}]!", bean.getClass().getName(), methodName, packetName, GatewayAttachment.class.getCanonicalName());
}
}
var protocolId = Short.MIN_VALUE;
try {
protocolId = ProtocolManager.protocolId(packetClazz);
} catch (Exception e) {
throw new RunException("[class:{}][protocolId:{}] has no registration, please register for this protocol", packetClazz.getSimpleName(), protocolId);
}
try {
var protocolId = ProtocolManager.protocolId(packetClazz);
// 将receiver注册到IProtocolRegistration
var protocolRegistration = ProtocolManager.getProtocol(protocolId);
AssertionUtils.notNull(protocolRegistration, "协议类[class:{}][protocolId:{}]没有注册", packetClazz.getSimpleName(), protocolId);
AssertionUtils.isNull(protocolRegistration.receiver(), "协议类[class:{}]被重复接收[at{}],一个协议只能对应一个被@PacketReceiver标注的方法"
, packetClazz.getSimpleName(), packetClazz.getSimpleName());
AssertionUtils.isNull(protocolRegistration.receiver(), "duplicate protocol registration, @PacketReceiver [class:{}] is repeatedly received [at{}]", packetClazz.getSimpleName(), packetClazz.getSimpleName());
var receiverDefinition = new PacketReceiverDefinition(bean, method, packetClazz, attachmentClazz);
var enhanceReceiverDefinition = EnhanceUtils.createPacketReceiver(receiverDefinition);
@@ -133,7 +122,7 @@ public abstract class PacketBus {
ReflectionUtils.makeAccessible(receiverField);
ReflectionUtils.setField(receiverField, protocolRegistration, enhanceReceiverDefinition);
} catch (Throwable t) {
throw new RunException(t, "解析协议类[class:{}]未知异常", packetClazz.getSimpleName());
throw new RunException(t, "Registration protocol [class:{}] unknown exception", packetClazz.getSimpleName());
}
}
}
@@ -22,9 +22,10 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReferenceArray;
/**
* 同步或异步的调用控制器,同步和异步调用的信号沟通桥梁
* EN:Synchronous or asynchronous call controller, synchronous and asynchronous call signal communication bridge
* CN:同步或异步的调用控制器,同步和异步调用的信号沟通桥梁
*
* @author jaysunxiao
* @author godotg
* @version 3.0
*/
public class SignalBridge {
@@ -35,20 +36,16 @@ public class SignalBridge {
private static final int SIGNAL_MASK = 0B00000000_00000000_01111111_11111111;
/**
* 用来保存同步或异步请求的SignalAttachment附加包,signalId和SIGNAL_MASK取与的结果hash作为数组索引,使用AtomicReferenceArray只是为了提升性能
*/
private static final AtomicReferenceArray<SignalAttachment> signalAttachmentArray = new AtomicReferenceArray<>(SIGNAL_MASK + 1);
/**
* 用来保存同步或异步请求的SignalAttachment附加包,keysignalId
* keysignalId
*/
private static final Map<Integer, SignalAttachment> signalAttachmentMap = new ConcurrentHashMap<>(1000);
private static final AtomicReferenceArray<SignalAttachment> signalAttachmentArray = new AtomicReferenceArray<>(SIGNAL_MASK + 1);
public static void addSignalAttachment(SignalAttachment signalAttachment) {
var signalId = signalAttachment.getSignalId();
var hash = signalId & SIGNAL_MASK;
// 使用AtomicReferenceArray只是为了提升性能,仅使用ConcurrentHashMap依然可以运行
// Using an Atomic Reference Array is just to improve performance, and only using a ConcurrentHashMap will still work
if (signalAttachmentArray.compareAndSet(hash, null, signalAttachment)) {
return;
}