mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-08-06 00:24:08 +00:00
perf[net]: Wrong configuration gives appropriate hints
This commit is contained in:
@@ -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, 唯一表示一个Attachment,hashcode() and equals() 也通过signalId计算
|
||||
* EN:Unique identification of a packet, unique representation of an attachment, hashcode() and equals() equals signalId value
|
||||
* CN:唯一标识一个packet, 唯一表示一个Attachment,hashcode() 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 {
|
||||
|
||||
/**
|
||||
* 一个controller的bean
|
||||
* 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附加包,key:signalId
|
||||
* key:signalId
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user