From 9e442a32976ddd288d1b5f0b970f11e3a7cac255 Mon Sep 17 00:00:00 2001
From: giant <553954594@qq.com>
Date: Fri, 10 Jan 2025 20:15:10 +0800
Subject: [PATCH 1/8] =?UTF-8?q?socket=E6=8E=A5=E5=8F=A3=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E5=8F=82=E6=95=B0=E6=8E=A5?=
=?UTF-8?q?=E5=8F=97=E6=96=B9=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 2 +-
.../org/yeauty/pojo/PojoMethodMapping.java | 740 +++++++++---------
.../standard/ServerEndpointExporter.java | 513 ++++++------
3 files changed, 631 insertions(+), 624 deletions(-)
diff --git a/pom.xml b/pom.xml
index 47ef3fb..4825fc2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
org.yeauty
netty-websocket-spring-boot-starter
- 0.12.0
+ 0.13.0
netty-websocket-spring-boot-starter
diff --git a/src/main/java/org/yeauty/pojo/PojoMethodMapping.java b/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
index 489b977..841e8e9 100755
--- a/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
+++ b/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
@@ -1,371 +1,371 @@
-package org.yeauty.pojo;
-
-import io.netty.channel.Channel;
-import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
-import org.springframework.beans.factory.support.AbstractBeanFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.core.DefaultParameterNameDiscoverer;
-import org.springframework.core.MethodParameter;
-import org.springframework.core.ParameterNameDiscoverer;
-import org.yeauty.annotation.*;
-import org.yeauty.exception.DeploymentException;
-import org.yeauty.support.*;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class PojoMethodMapping {
-
- private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
-
- private final Method beforeHandshake;
- private final Method onOpen;
- private final Method onClose;
- private final Method onError;
- private final Method onMessage;
- private final Method onBinary;
- private final Method onEvent;
- private final MethodParameter[] beforeHandshakeParameters;
- private final MethodParameter[] onOpenParameters;
- private final MethodParameter[] onCloseParameters;
- private final MethodParameter[] onErrorParameters;
- private final MethodParameter[] onMessageParameters;
- private final MethodParameter[] onBinaryParameters;
- private final MethodParameter[] onEventParameters;
- private final MethodArgumentResolver[] beforeHandshakeArgResolvers;
- private final MethodArgumentResolver[] onOpenArgResolvers;
- private final MethodArgumentResolver[] onCloseArgResolvers;
- private final MethodArgumentResolver[] onErrorArgResolvers;
- private final MethodArgumentResolver[] onMessageArgResolvers;
- private final MethodArgumentResolver[] onBinaryArgResolvers;
- private final MethodArgumentResolver[] onEventArgResolvers;
- private final Class pojoClazz;
- private final ApplicationContext applicationContext;
- private final AbstractBeanFactory beanFactory;
-
- public PojoMethodMapping(Class> pojoClazz, ApplicationContext context, AbstractBeanFactory beanFactory) throws DeploymentException {
- this.applicationContext = context;
- this.pojoClazz = pojoClazz;
- this.beanFactory = beanFactory;
- Method handshake = null;
- Method open = null;
- Method close = null;
- Method error = null;
- Method message = null;
- Method binary = null;
- Method event = null;
- Method[] pojoClazzMethods = null;
- Class> currentClazz = pojoClazz;
- while (!currentClazz.equals(Object.class)) {
- Method[] currentClazzMethods = currentClazz.getDeclaredMethods();
- if (currentClazz == pojoClazz) {
- pojoClazzMethods = currentClazzMethods;
- }
- for (Method method : currentClazzMethods) {
- if (method.getAnnotation(BeforeHandshake.class) != null) {
- checkPublic(method);
- if (handshake == null) {
- handshake = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(handshake, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation BeforeHandshake");
- }
- }
- } else if (method.getAnnotation(OnOpen.class) != null) {
- checkPublic(method);
- if (open == null) {
- open = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(open, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation OnOpen");
- }
- }
- } else if (method.getAnnotation(OnClose.class) != null) {
- checkPublic(method);
- if (close == null) {
- close = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(close, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation OnClose");
- }
- }
- } else if (method.getAnnotation(OnError.class) != null) {
- checkPublic(method);
- if (error == null) {
- error = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(error, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation OnError");
- }
- }
- } else if (method.getAnnotation(OnMessage.class) != null) {
- checkPublic(method);
- if (message == null) {
- message = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(message, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation onMessage");
- }
- }
- } else if (method.getAnnotation(OnBinary.class) != null) {
- checkPublic(method);
- if (binary == null) {
- binary = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(binary, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation OnBinary");
- }
- }
- } else if (method.getAnnotation(OnEvent.class) != null) {
- checkPublic(method);
- if (event == null) {
- event = method;
- } else {
- if (currentClazz == pojoClazz ||
- !isMethodOverride(event, method)) {
- // Duplicate annotation
- throw new DeploymentException(
- "pojoMethodMapping.duplicateAnnotation OnEvent");
- }
- }
- } else {
- // Method not annotated
- }
- }
- currentClazz = currentClazz.getSuperclass();
- }
- // If the methods are not on pojoClazz and they are overridden
- // by a non annotated method in pojoClazz, they should be ignored
- if (handshake != null && handshake.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, handshake, BeforeHandshake.class)) {
- handshake = null;
- }
- }
- if (open != null && open.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, open, OnOpen.class)) {
- open = null;
- }
- }
- if (close != null && close.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, close, OnClose.class)) {
- close = null;
- }
- }
- if (error != null && error.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, error, OnError.class)) {
- error = null;
- }
- }
- if (message != null && message.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, message, OnMessage.class)) {
- message = null;
- }
- }
- if (binary != null && binary.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, binary, OnBinary.class)) {
- binary = null;
- }
- }
- if (event != null && event.getDeclaringClass() != pojoClazz) {
- if (isOverridenWithoutAnnotation(pojoClazzMethods, event, OnEvent.class)) {
- event = null;
- }
- }
-
- this.beforeHandshake = handshake;
- this.onOpen = open;
- this.onClose = close;
- this.onError = error;
- this.onMessage = message;
- this.onBinary = binary;
- this.onEvent = event;
- beforeHandshakeParameters = getParameters(beforeHandshake);
- onOpenParameters = getParameters(onOpen);
- onCloseParameters = getParameters(onClose);
- onMessageParameters = getParameters(onMessage);
- onErrorParameters = getParameters(onError);
- onBinaryParameters = getParameters(onBinary);
- onEventParameters = getParameters(onEvent);
- beforeHandshakeArgResolvers = getResolvers(beforeHandshakeParameters);
- onOpenArgResolvers = getResolvers(onOpenParameters);
- onCloseArgResolvers = getResolvers(onCloseParameters);
- onMessageArgResolvers = getResolvers(onMessageParameters);
- onErrorArgResolvers = getResolvers(onErrorParameters);
- onBinaryArgResolvers = getResolvers(onBinaryParameters);
- onEventArgResolvers = getResolvers(onEventParameters);
- }
-
- private void checkPublic(Method m) throws DeploymentException {
- if (!Modifier.isPublic(m.getModifiers())) {
- throw new DeploymentException(
- "pojoMethodMapping.methodNotPublic " + m.getName());
- }
- }
-
- private boolean isMethodOverride(Method method1, Method method2) {
- return (method1.getName().equals(method2.getName())
- && method1.getReturnType().equals(method2.getReturnType())
- && Arrays.equals(method1.getParameterTypes(), method2.getParameterTypes()));
- }
-
- private boolean isOverridenWithoutAnnotation(Method[] methods, Method superclazzMethod, Class extends Annotation> annotation) {
- for (Method method : methods) {
- if (isMethodOverride(method, superclazzMethod)
- && (method.getAnnotation(annotation) == null)) {
- return true;
- }
- }
- return false;
- }
-
- Object getEndpointInstance() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
- Object implement = pojoClazz.getDeclaredConstructor().newInstance();
- AutowiredAnnotationBeanPostProcessor postProcessor = applicationContext.getBean(AutowiredAnnotationBeanPostProcessor.class);
- postProcessor.postProcessPropertyValues(null, null, implement, null);
- return implement;
- }
-
- Method getBeforeHandshake() {
- return beforeHandshake;
- }
-
- Object[] getBeforeHandshakeArgs(Channel channel, FullHttpRequest req) throws Exception {
- return getMethodArgumentValues(channel, req, beforeHandshakeParameters, beforeHandshakeArgResolvers);
- }
-
- Method getOnOpen() {
- return onOpen;
- }
-
- Object[] getOnOpenArgs(Channel channel, FullHttpRequest req) throws Exception {
- return getMethodArgumentValues(channel, req, onOpenParameters, onOpenArgResolvers);
- }
-
- MethodArgumentResolver[] getOnOpenArgResolvers() {
- return onOpenArgResolvers;
- }
-
- Method getOnClose() {
- return onClose;
- }
-
- Object[] getOnCloseArgs(Channel channel) throws Exception {
- return getMethodArgumentValues(channel, null, onCloseParameters, onCloseArgResolvers);
- }
-
- Method getOnError() {
- return onError;
- }
-
- Object[] getOnErrorArgs(Channel channel, Throwable throwable) throws Exception {
- return getMethodArgumentValues(channel, throwable, onErrorParameters, onErrorArgResolvers);
- }
-
- Method getOnMessage() {
- return onMessage;
- }
-
- Object[] getOnMessageArgs(Channel channel, TextWebSocketFrame textWebSocketFrame) throws Exception {
- return getMethodArgumentValues(channel, textWebSocketFrame, onMessageParameters, onMessageArgResolvers);
- }
-
- Method getOnBinary() {
- return onBinary;
- }
-
- Object[] getOnBinaryArgs(Channel channel, BinaryWebSocketFrame binaryWebSocketFrame) throws Exception {
- return getMethodArgumentValues(channel, binaryWebSocketFrame, onBinaryParameters, onBinaryArgResolvers);
- }
-
- Method getOnEvent() {
- return onEvent;
- }
-
- Object[] getOnEventArgs(Channel channel, Object evt) throws Exception {
- return getMethodArgumentValues(channel, evt, onEventParameters, onEventArgResolvers);
- }
-
- private Object[] getMethodArgumentValues(Channel channel, Object object, MethodParameter[] parameters, MethodArgumentResolver[] resolvers) throws Exception {
- Object[] objects = new Object[parameters.length];
- for (int i = 0; i < parameters.length; i++) {
- MethodParameter parameter = parameters[i];
- MethodArgumentResolver resolver = resolvers[i];
- Object arg = resolver.resolveArgument(parameter, channel, object);
- objects[i] = arg;
- }
- return objects;
- }
-
- private MethodArgumentResolver[] getResolvers(MethodParameter[] parameters) throws DeploymentException {
- MethodArgumentResolver[] methodArgumentResolvers = new MethodArgumentResolver[parameters.length];
- List resolvers = getDefaultResolvers();
- for (int i = 0; i < parameters.length; i++) {
- MethodParameter parameter = parameters[i];
- for (MethodArgumentResolver resolver : resolvers) {
- if (resolver.supportsParameter(parameter)) {
- methodArgumentResolvers[i] = resolver;
- break;
- }
- }
- if (methodArgumentResolvers[i] == null) {
- throw new DeploymentException("pojoMethodMapping.paramClassIncorrect parameter name : " + parameter.getParameterName());
- }
- }
- return methodArgumentResolvers;
- }
-
- private List getDefaultResolvers() {
- List resolvers = new ArrayList<>();
- resolvers.add(new SessionMethodArgumentResolver());
- resolvers.add(new HttpHeadersMethodArgumentResolver());
- resolvers.add(new TextMethodArgumentResolver());
- resolvers.add(new ThrowableMethodArgumentResolver());
- resolvers.add(new ByteMethodArgumentResolver());
- resolvers.add(new RequestParamMapMethodArgumentResolver());
- resolvers.add(new RequestParamMethodArgumentResolver(beanFactory));
- resolvers.add(new PathVariableMapMethodArgumentResolver());
- resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
- resolvers.add(new EventMethodArgumentResolver(beanFactory));
- return resolvers;
- }
-
- private static MethodParameter[] getParameters(Method m) {
- if (m == null) {
- return new MethodParameter[0];
- }
- int count = m.getParameterCount();
- MethodParameter[] result = new MethodParameter[count];
- for (int i = 0; i < count; i++) {
- MethodParameter methodParameter = new MethodParameter(m, i);
- methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
- result[i] = methodParameter;
- }
- return result;
- }
+package org.yeauty.pojo;
+
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.FullHttpRequest;
+import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.MethodParameter;
+import org.springframework.core.ParameterNameDiscoverer;
+import org.yeauty.annotation.*;
+import org.yeauty.exception.DeploymentException;
+import org.yeauty.support.*;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PojoMethodMapping {
+
+ private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
+
+ private final Method beforeHandshake;
+ private final Method onOpen;
+ private final Method onClose;
+ private final Method onError;
+ private final Method onMessage;
+ private final Method onBinary;
+ private final Method onEvent;
+ private final MethodParameter[] beforeHandshakeParameters;
+ private final MethodParameter[] onOpenParameters;
+ private final MethodParameter[] onCloseParameters;
+ private final MethodParameter[] onErrorParameters;
+ private final MethodParameter[] onMessageParameters;
+ private final MethodParameter[] onBinaryParameters;
+ private final MethodParameter[] onEventParameters;
+ private final MethodArgumentResolver[] beforeHandshakeArgResolvers;
+ private final MethodArgumentResolver[] onOpenArgResolvers;
+ private final MethodArgumentResolver[] onCloseArgResolvers;
+ private final MethodArgumentResolver[] onErrorArgResolvers;
+ private final MethodArgumentResolver[] onMessageArgResolvers;
+ private final MethodArgumentResolver[] onBinaryArgResolvers;
+ private final MethodArgumentResolver[] onEventArgResolvers;
+ private final Class pojoClazz;
+ private final ApplicationContext applicationContext;
+ private final AbstractBeanFactory beanFactory;
+
+ public PojoMethodMapping(Class> pojoClazz, ApplicationContext context, AbstractBeanFactory beanFactory) throws DeploymentException {
+ this.applicationContext = context;
+ this.pojoClazz = pojoClazz;
+ this.beanFactory = beanFactory;
+ Method handshake = null;
+ Method open = null;
+ Method close = null;
+ Method error = null;
+ Method message = null;
+ Method binary = null;
+ Method event = null;
+ Method[] pojoClazzMethods = null;
+ Class> currentClazz = pojoClazz;
+ while (!currentClazz.equals(Object.class)) {
+ Method[] currentClazzMethods = currentClazz.getDeclaredMethods();
+ if (currentClazz == pojoClazz) {
+ pojoClazzMethods = currentClazzMethods;
+ }
+ for (Method method : currentClazzMethods) {
+ if (method.getAnnotation(BeforeHandshake.class) != null) {
+ checkPublic(method);
+ if (handshake == null) {
+ handshake = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(handshake, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation BeforeHandshake");
+ }
+ }
+ } else if (method.getAnnotation(OnOpen.class) != null) {
+ checkPublic(method);
+ if (open == null) {
+ open = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(open, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation OnOpen");
+ }
+ }
+ } else if (method.getAnnotation(OnClose.class) != null) {
+ checkPublic(method);
+ if (close == null) {
+ close = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(close, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation OnClose");
+ }
+ }
+ } else if (method.getAnnotation(OnError.class) != null) {
+ checkPublic(method);
+ if (error == null) {
+ error = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(error, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation OnError");
+ }
+ }
+ } else if (method.getAnnotation(OnMessage.class) != null) {
+ checkPublic(method);
+ if (message == null) {
+ message = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(message, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation onMessage");
+ }
+ }
+ } else if (method.getAnnotation(OnBinary.class) != null) {
+ checkPublic(method);
+ if (binary == null) {
+ binary = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(binary, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation OnBinary");
+ }
+ }
+ } else if (method.getAnnotation(OnEvent.class) != null) {
+ checkPublic(method);
+ if (event == null) {
+ event = method;
+ } else {
+ if (currentClazz == pojoClazz ||
+ !isMethodOverride(event, method)) {
+ // Duplicate annotation
+ throw new DeploymentException(
+ "pojoMethodMapping.duplicateAnnotation OnEvent");
+ }
+ }
+ } else {
+ // Method not annotated
+ }
+ }
+ currentClazz = currentClazz.getSuperclass();
+ }
+ // If the methods are not on pojoClazz and they are overridden
+ // by a non annotated method in pojoClazz, they should be ignored
+ if (handshake != null && handshake.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, handshake, BeforeHandshake.class)) {
+ handshake = null;
+ }
+ }
+ if (open != null && open.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, open, OnOpen.class)) {
+ open = null;
+ }
+ }
+ if (close != null && close.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, close, OnClose.class)) {
+ close = null;
+ }
+ }
+ if (error != null && error.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, error, OnError.class)) {
+ error = null;
+ }
+ }
+ if (message != null && message.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, message, OnMessage.class)) {
+ message = null;
+ }
+ }
+ if (binary != null && binary.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, binary, OnBinary.class)) {
+ binary = null;
+ }
+ }
+ if (event != null && event.getDeclaringClass() != pojoClazz) {
+ if (isOverridenWithoutAnnotation(pojoClazzMethods, event, OnEvent.class)) {
+ event = null;
+ }
+ }
+
+ this.beforeHandshake = handshake;
+ this.onOpen = open;
+ this.onClose = close;
+ this.onError = error;
+ this.onMessage = message;
+ this.onBinary = binary;
+ this.onEvent = event;
+ beforeHandshakeParameters = getParameters(beforeHandshake);
+ onOpenParameters = getParameters(onOpen);
+ onCloseParameters = getParameters(onClose);
+ onMessageParameters = getParameters(onMessage);
+ onErrorParameters = getParameters(onError);
+ onBinaryParameters = getParameters(onBinary);
+ onEventParameters = getParameters(onEvent);
+ beforeHandshakeArgResolvers = getResolvers(beforeHandshakeParameters);
+ onOpenArgResolvers = getResolvers(onOpenParameters);
+ onCloseArgResolvers = getResolvers(onCloseParameters);
+ onMessageArgResolvers = getResolvers(onMessageParameters);
+ onErrorArgResolvers = getResolvers(onErrorParameters);
+ onBinaryArgResolvers = getResolvers(onBinaryParameters);
+ onEventArgResolvers = getResolvers(onEventParameters);
+ }
+
+ private void checkPublic(Method m) throws DeploymentException {
+ if (!Modifier.isPublic(m.getModifiers())) {
+ throw new DeploymentException(
+ "pojoMethodMapping.methodNotPublic " + m.getName());
+ }
+ }
+
+ private boolean isMethodOverride(Method method1, Method method2) {
+ return (method1.getName().equals(method2.getName())
+ && method1.getReturnType().equals(method2.getReturnType())
+ && Arrays.equals(method1.getParameterTypes(), method2.getParameterTypes()));
+ }
+
+ private boolean isOverridenWithoutAnnotation(Method[] methods, Method superclazzMethod, Class extends Annotation> annotation) {
+ for (Method method : methods) {
+ if (isMethodOverride(method, superclazzMethod)
+ && (method.getAnnotation(annotation) == null)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ Object getEndpointInstance() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ Object implement = pojoClazz.getDeclaredConstructor().newInstance();
+ AutowiredAnnotationBeanPostProcessor postProcessor = applicationContext.getBean(AutowiredAnnotationBeanPostProcessor.class);
+ postProcessor.postProcessPropertyValues(null, null, implement, null);
+ return implement;
+ }
+
+ Method getBeforeHandshake() {
+ return beforeHandshake;
+ }
+
+ Object[] getBeforeHandshakeArgs(Channel channel, FullHttpRequest req) throws Exception {
+ return getMethodArgumentValues(channel, req, beforeHandshakeParameters, beforeHandshakeArgResolvers);
+ }
+
+ Method getOnOpen() {
+ return onOpen;
+ }
+
+ Object[] getOnOpenArgs(Channel channel, FullHttpRequest req) throws Exception {
+ return getMethodArgumentValues(channel, req, onOpenParameters, onOpenArgResolvers);
+ }
+
+ MethodArgumentResolver[] getOnOpenArgResolvers() {
+ return onOpenArgResolvers;
+ }
+
+ Method getOnClose() {
+ return onClose;
+ }
+
+ Object[] getOnCloseArgs(Channel channel) throws Exception {
+ return getMethodArgumentValues(channel, null, onCloseParameters, onCloseArgResolvers);
+ }
+
+ Method getOnError() {
+ return onError;
+ }
+
+ Object[] getOnErrorArgs(Channel channel, Throwable throwable) throws Exception {
+ return getMethodArgumentValues(channel, throwable, onErrorParameters, onErrorArgResolvers);
+ }
+
+ Method getOnMessage() {
+ return onMessage;
+ }
+
+ Object[] getOnMessageArgs(Channel channel, TextWebSocketFrame textWebSocketFrame) throws Exception {
+ return getMethodArgumentValues(channel, textWebSocketFrame, onMessageParameters, onMessageArgResolvers);
+ }
+
+ Method getOnBinary() {
+ return onBinary;
+ }
+
+ Object[] getOnBinaryArgs(Channel channel, BinaryWebSocketFrame binaryWebSocketFrame) throws Exception {
+ return getMethodArgumentValues(channel, binaryWebSocketFrame, onBinaryParameters, onBinaryArgResolvers);
+ }
+
+ Method getOnEvent() {
+ return onEvent;
+ }
+
+ Object[] getOnEventArgs(Channel channel, Object evt) throws Exception {
+ return getMethodArgumentValues(channel, evt, onEventParameters, onEventArgResolvers);
+ }
+
+ private Object[] getMethodArgumentValues(Channel channel, Object object, MethodParameter[] parameters, MethodArgumentResolver[] resolvers) throws Exception {
+ Object[] objects = new Object[parameters.length];
+ for (int i = 0; i < parameters.length; i++) {
+ MethodParameter parameter = parameters[i];
+ MethodArgumentResolver resolver = resolvers[i];
+ Object arg = resolver.resolveArgument(parameter, channel, object);
+ objects[i] = arg;
+ }
+ return objects;
+ }
+
+ private MethodArgumentResolver[] getResolvers(MethodParameter[] parameters) throws DeploymentException {
+ MethodArgumentResolver[] methodArgumentResolvers = new MethodArgumentResolver[parameters.length];
+ List resolvers = getDefaultResolvers();
+ for (int i = 0; i < parameters.length; i++) {
+ MethodParameter parameter = parameters[i];
+ for (MethodArgumentResolver resolver : resolvers) {
+ if (resolver.supportsParameter(parameter)) {
+ methodArgumentResolvers[i] = resolver;
+ break;
+ }
+ }
+ if (methodArgumentResolvers[i] == null) {
+ throw new DeploymentException("pojoMethodMapping.paramClassIncorrect parameter name : " + parameter.getParameterName());
+ }
+ }
+ return methodArgumentResolvers;
+ }
+
+ protected List getDefaultResolvers() {
+ List resolvers = new ArrayList<>();
+ resolvers.add(new SessionMethodArgumentResolver());
+ resolvers.add(new HttpHeadersMethodArgumentResolver());
+ resolvers.add(new TextMethodArgumentResolver());
+ resolvers.add(new ThrowableMethodArgumentResolver());
+ resolvers.add(new ByteMethodArgumentResolver());
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new RequestParamMethodArgumentResolver(beanFactory));
+ resolvers.add(new PathVariableMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
+ resolvers.add(new EventMethodArgumentResolver(beanFactory));
+ return resolvers;
+ }
+
+ private static MethodParameter[] getParameters(Method m) {
+ if (m == null) {
+ return new MethodParameter[0];
+ }
+ int count = m.getParameterCount();
+ MethodParameter[] result = new MethodParameter[count];
+ for (int i = 0; i < count; i++) {
+ MethodParameter methodParameter = new MethodParameter(m, i);
+ methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
+ result[i] = methodParameter;
+ }
+ return result;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/yeauty/standard/ServerEndpointExporter.java b/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
index ef85bb9..90682bb 100755
--- a/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
+++ b/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
@@ -1,253 +1,260 @@
-package org.yeauty.standard;
-
-import org.springframework.beans.TypeConverter;
-import org.springframework.beans.TypeMismatchException;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
-import org.springframework.beans.factory.SmartInitializingSingleton;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.config.BeanExpressionContext;
-import org.springframework.beans.factory.config.BeanExpressionResolver;
-import org.springframework.beans.factory.support.AbstractBeanFactory;
-import org.springframework.beans.factory.support.BeanDefinitionRegistry;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ResourceLoaderAware;
-import org.springframework.context.support.ApplicationObjectSupport;
-import org.springframework.core.annotation.AnnotatedElementUtils;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.ResourceLoader;
-import org.springframework.util.ClassUtils;
-import org.yeauty.annotation.EnableWebSocket;
-import org.yeauty.annotation.ServerEndpoint;
-import org.yeauty.exception.DeploymentException;
-import org.yeauty.pojo.PojoEndpointServer;
-import org.yeauty.pojo.PojoMethodMapping;
-
-import javax.net.ssl.SSLException;
-import java.net.InetSocketAddress;
-import java.util.*;
-
-/**
- * @author Yeauty
- */
-public class ServerEndpointExporter extends ApplicationObjectSupport implements SmartInitializingSingleton, BeanFactoryAware, ResourceLoaderAware {
-
- @Autowired
- Environment environment;
-
- private AbstractBeanFactory beanFactory;
-
- private ResourceLoader resourceLoader;
-
- private final Map addressWebsocketServerMap = new HashMap<>();
-
- @Override
- public void afterSingletonsInstantiated() {
- registerEndpoints();
- }
-
- @Override
- public void setBeanFactory(BeanFactory beanFactory) {
- if (!(beanFactory instanceof AbstractBeanFactory)) {
- throw new IllegalArgumentException(
- "AutowiredAnnotationBeanPostProcessor requires a AbstractBeanFactory: " + beanFactory);
- }
- this.beanFactory = (AbstractBeanFactory) beanFactory;
- }
-
- protected void registerEndpoints() {
- ApplicationContext context = getApplicationContext();
-
- scanPackage(context);
-
- String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);
- Set> endpointClasses = new LinkedHashSet<>();
- for (String beanName : endpointBeanNames) {
- endpointClasses.add(context.getType(beanName));
- }
-
- for (Class> endpointClass : endpointClasses) {
- if (ClassUtils.isCglibProxyClass(endpointClass)) {
- registerEndpoint(endpointClass.getSuperclass());
- } else {
- registerEndpoint(endpointClass);
- }
- }
-
- init();
- }
-
- private void scanPackage(ApplicationContext context) {
- String[] basePackages = null;
-
- String[] enableWebSocketBeanNames = context.getBeanNamesForAnnotation(EnableWebSocket.class);
- if (enableWebSocketBeanNames.length != 0) {
- for (String enableWebSocketBeanName : enableWebSocketBeanNames) {
- Object enableWebSocketBean = context.getBean(enableWebSocketBeanName);
- EnableWebSocket enableWebSocket = AnnotationUtils.findAnnotation(enableWebSocketBean.getClass(), EnableWebSocket.class);
- assert enableWebSocket != null;
- if (enableWebSocket.scanBasePackages().length != 0) {
- basePackages = enableWebSocket.scanBasePackages();
- break;
- }
- }
- }
-
- // use @SpringBootApplication package
- if (basePackages == null) {
- String[] springBootApplicationBeanName = context.getBeanNamesForAnnotation(SpringBootApplication.class);
- Object springBootApplicationBean = context.getBean(springBootApplicationBeanName[0]);
- SpringBootApplication springBootApplication = AnnotationUtils.findAnnotation(springBootApplicationBean.getClass(), SpringBootApplication.class);
- assert springBootApplication != null;
- if (springBootApplication.scanBasePackages().length != 0) {
- basePackages = springBootApplication.scanBasePackages();
- } else {
- String packageName = ClassUtils.getPackageName(springBootApplicationBean.getClass().getName());
- basePackages = new String[1];
- basePackages[0] = packageName;
- }
- }
-
- EndpointClassPathScanner scanHandle = new EndpointClassPathScanner((BeanDefinitionRegistry) context, false);
- if (resourceLoader != null) {
- scanHandle.setResourceLoader(resourceLoader);
- }
-
- for (String basePackage : basePackages) {
- scanHandle.doScan(basePackage);
- }
- }
-
- private void init() {
- for (Map.Entry entry : addressWebsocketServerMap.entrySet()) {
- WebsocketServer websocketServer = entry.getValue();
- try {
- websocketServer.init();
- PojoEndpointServer pojoEndpointServer = websocketServer.getPojoEndpointServer();
- StringJoiner stringJoiner = new StringJoiner(",");
- pojoEndpointServer.getPathMatcherSet().forEach(pathMatcher -> stringJoiner.add("'" + pathMatcher.getPattern() + "'"));
- logger.info(String.format("\033[34mNetty WebSocket started on port: %s with context path(s): %s .\033[0m", pojoEndpointServer.getPort(), stringJoiner.toString()));
- } catch (InterruptedException e) {
- logger.error(String.format("websocket [%s] init fail", entry.getKey()), e);
- } catch (SSLException e) {
- logger.error(String.format("websocket [%s] ssl create fail", entry.getKey()), e);
-
- }
- }
- }
-
- private void registerEndpoint(Class> endpointClass) {
- ServerEndpoint annotation = AnnotatedElementUtils.findMergedAnnotation(endpointClass, ServerEndpoint.class);
- if (annotation == null) {
- throw new IllegalStateException("missingAnnotation ServerEndpoint");
- }
- ServerEndpointConfig serverEndpointConfig = buildConfig(annotation);
-
- ApplicationContext context = getApplicationContext();
- PojoMethodMapping pojoMethodMapping = null;
- try {
- pojoMethodMapping = new PojoMethodMapping(endpointClass, context, beanFactory);
- } catch (DeploymentException e) {
- throw new IllegalStateException("Failed to register ServerEndpointConfig: " + serverEndpointConfig, e);
- }
-
- InetSocketAddress inetSocketAddress = new InetSocketAddress(serverEndpointConfig.getHost(), serverEndpointConfig.getPort());
- String path = resolveAnnotationValue(annotation.value(), String.class, "path");
-
- WebsocketServer websocketServer = addressWebsocketServerMap.get(inetSocketAddress);
- if (websocketServer == null) {
- PojoEndpointServer pojoEndpointServer = new PojoEndpointServer(pojoMethodMapping, serverEndpointConfig, path);
- websocketServer = new WebsocketServer(pojoEndpointServer, serverEndpointConfig);
- addressWebsocketServerMap.put(inetSocketAddress, websocketServer);
- } else {
- websocketServer.getPojoEndpointServer().addPathPojoMethodMapping(path, pojoMethodMapping);
- }
- }
-
- private ServerEndpointConfig buildConfig(ServerEndpoint annotation) {
- String host = resolveAnnotationValue(annotation.host(), String.class, "host");
- int port = resolveAnnotationValue(annotation.port(), Integer.class, "port");
- String path = resolveAnnotationValue(annotation.value(), String.class, "value");
- int bossLoopGroupThreads = resolveAnnotationValue(annotation.bossLoopGroupThreads(), Integer.class, "bossLoopGroupThreads");
- int workerLoopGroupThreads = resolveAnnotationValue(annotation.workerLoopGroupThreads(), Integer.class, "workerLoopGroupThreads");
- boolean useCompressionHandler = resolveAnnotationValue(annotation.useCompressionHandler(), Boolean.class, "useCompressionHandler");
-
- int optionConnectTimeoutMillis = resolveAnnotationValue(annotation.optionConnectTimeoutMillis(), Integer.class, "optionConnectTimeoutMillis");
- int optionSoBacklog = resolveAnnotationValue(annotation.optionSoBacklog(), Integer.class, "optionSoBacklog");
-
- int childOptionWriteSpinCount = resolveAnnotationValue(annotation.childOptionWriteSpinCount(), Integer.class, "childOptionWriteSpinCount");
- int childOptionWriteBufferHighWaterMark = resolveAnnotationValue(annotation.childOptionWriteBufferHighWaterMark(), Integer.class, "childOptionWriteBufferHighWaterMark");
- int childOptionWriteBufferLowWaterMark = resolveAnnotationValue(annotation.childOptionWriteBufferLowWaterMark(), Integer.class, "childOptionWriteBufferLowWaterMark");
- int childOptionSoRcvbuf = resolveAnnotationValue(annotation.childOptionSoRcvbuf(), Integer.class, "childOptionSoRcvbuf");
- int childOptionSoSndbuf = resolveAnnotationValue(annotation.childOptionSoSndbuf(), Integer.class, "childOptionSoSndbuf");
- boolean childOptionTcpNodelay = resolveAnnotationValue(annotation.childOptionTcpNodelay(), Boolean.class, "childOptionTcpNodelay");
- boolean childOptionSoKeepalive = resolveAnnotationValue(annotation.childOptionSoKeepalive(), Boolean.class, "childOptionSoKeepalive");
- int childOptionSoLinger = resolveAnnotationValue(annotation.childOptionSoLinger(), Integer.class, "childOptionSoLinger");
- boolean childOptionAllowHalfClosure = resolveAnnotationValue(annotation.childOptionAllowHalfClosure(), Boolean.class, "childOptionAllowHalfClosure");
-
- int readerIdleTimeSeconds = resolveAnnotationValue(annotation.readerIdleTimeSeconds(), Integer.class, "readerIdleTimeSeconds");
- int writerIdleTimeSeconds = resolveAnnotationValue(annotation.writerIdleTimeSeconds(), Integer.class, "writerIdleTimeSeconds");
- int allIdleTimeSeconds = resolveAnnotationValue(annotation.allIdleTimeSeconds(), Integer.class, "allIdleTimeSeconds");
-
- int maxFramePayloadLength = resolveAnnotationValue(annotation.maxFramePayloadLength(), Integer.class, "maxFramePayloadLength");
-
- boolean useEventExecutorGroup = resolveAnnotationValue(annotation.useEventExecutorGroup(), Boolean.class, "useEventExecutorGroup");
- int eventExecutorGroupThreads = resolveAnnotationValue(annotation.eventExecutorGroupThreads(), Integer.class, "eventExecutorGroupThreads");
-
- String sslKeyPassword = resolveAnnotationValue(annotation.sslKeyPassword(), String.class, "sslKeyPassword");
- String sslKeyStore = resolveAnnotationValue(annotation.sslKeyStore(), String.class, "sslKeyStore");
- String sslKeyStorePassword = resolveAnnotationValue(annotation.sslKeyStorePassword(), String.class, "sslKeyStorePassword");
- String sslKeyStoreType = resolveAnnotationValue(annotation.sslKeyStoreType(), String.class, "sslKeyStoreType");
- String sslTrustStore = resolveAnnotationValue(annotation.sslTrustStore(), String.class, "sslTrustStore");
- String sslTrustStorePassword = resolveAnnotationValue(annotation.sslTrustStorePassword(), String.class, "sslTrustStorePassword");
- String sslTrustStoreType = resolveAnnotationValue(annotation.sslTrustStoreType(), String.class, "sslTrustStoreType");
-
- String[] corsOrigins = annotation.corsOrigins();
- if (corsOrigins.length != 0) {
- for (int i = 0; i < corsOrigins.length; i++) {
- corsOrigins[i] = resolveAnnotationValue(corsOrigins[i], String.class, "corsOrigins");
- }
- }
- Boolean corsAllowCredentials = resolveAnnotationValue(annotation.corsAllowCredentials(), Boolean.class, "corsAllowCredentials");
-
- ServerEndpointConfig serverEndpointConfig = new ServerEndpointConfig(host, port, bossLoopGroupThreads, workerLoopGroupThreads
- , useCompressionHandler, optionConnectTimeoutMillis, optionSoBacklog, childOptionWriteSpinCount, childOptionWriteBufferHighWaterMark
- , childOptionWriteBufferLowWaterMark, childOptionSoRcvbuf, childOptionSoSndbuf, childOptionTcpNodelay, childOptionSoKeepalive
- , childOptionSoLinger, childOptionAllowHalfClosure, readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds
- , maxFramePayloadLength, useEventExecutorGroup, eventExecutorGroupThreads
- , sslKeyPassword, sslKeyStore, sslKeyStorePassword, sslKeyStoreType
- , sslTrustStore, sslTrustStorePassword, sslTrustStoreType
- , corsOrigins, corsAllowCredentials);
-
- return serverEndpointConfig;
- }
-
- private T resolveAnnotationValue(Object value, Class requiredType, String paramName) {
- if (value == null) {
- return null;
- }
- TypeConverter typeConverter = beanFactory.getTypeConverter();
-
- if (value instanceof String) {
- String strVal = beanFactory.resolveEmbeddedValue((String) value);
- BeanExpressionResolver beanExpressionResolver = beanFactory.getBeanExpressionResolver();
- if (beanExpressionResolver != null) {
- value = beanExpressionResolver.evaluate(strVal, new BeanExpressionContext(beanFactory, null));
- } else {
- value = strVal;
- }
- }
- try {
- return typeConverter.convertIfNecessary(value, requiredType);
- } catch (TypeMismatchException e) {
- throw new IllegalArgumentException("Failed to convert value of parameter '" + paramName + "' to required type '" + requiredType.getName() + "'");
- }
- }
-
- @Override
- public void setResourceLoader(ResourceLoader resourceLoader) {
- this.resourceLoader = resourceLoader;
- }
-}
+package org.yeauty.standard;
+
+import org.springframework.beans.TypeConverter;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanExpressionContext;
+import org.springframework.beans.factory.config.BeanExpressionResolver;
+import org.springframework.beans.factory.support.AbstractBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.context.support.ApplicationObjectSupport;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.ClassUtils;
+import org.yeauty.annotation.EnableWebSocket;
+import org.yeauty.annotation.ServerEndpoint;
+import org.yeauty.exception.DeploymentException;
+import org.yeauty.pojo.PojoEndpointServer;
+import org.yeauty.pojo.PojoMethodMapping;
+
+import javax.net.ssl.SSLException;
+import java.net.InetSocketAddress;
+import java.util.*;
+
+/**
+ * @author Yeauty
+ */
+public class ServerEndpointExporter extends ApplicationObjectSupport implements SmartInitializingSingleton, BeanFactoryAware, ResourceLoaderAware {
+
+ @Autowired
+ Environment environment;
+
+ protected AbstractBeanFactory beanFactory;
+
+ private ResourceLoader resourceLoader;
+
+ private final Map addressWebsocketServerMap = new HashMap<>();
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ registerEndpoints();
+ }
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) {
+ if (!(beanFactory instanceof AbstractBeanFactory)) {
+ throw new IllegalArgumentException(
+ "AutowiredAnnotationBeanPostProcessor requires a AbstractBeanFactory: " + beanFactory);
+ }
+ this.beanFactory = (AbstractBeanFactory) beanFactory;
+ }
+
+ protected void registerEndpoints() {
+ ApplicationContext context = getApplicationContext();
+
+ scanPackage(context);
+
+ String[] endpointBeanNames = context.getBeanNamesForAnnotation(ServerEndpoint.class);
+ Set> endpointClasses = new LinkedHashSet<>();
+ for (String beanName : endpointBeanNames) {
+ endpointClasses.add(context.getType(beanName));
+ }
+
+ for (Class> endpointClass : endpointClasses) {
+ if (ClassUtils.isCglibProxyClass(endpointClass)) {
+ registerEndpoint(endpointClass.getSuperclass());
+ } else {
+ registerEndpoint(endpointClass);
+ }
+ }
+
+ init();
+ }
+
+ private void scanPackage(ApplicationContext context) {
+ String[] basePackages = null;
+
+ String[] enableWebSocketBeanNames = context.getBeanNamesForAnnotation(EnableWebSocket.class);
+ if (enableWebSocketBeanNames.length != 0) {
+ for (String enableWebSocketBeanName : enableWebSocketBeanNames) {
+ Object enableWebSocketBean = context.getBean(enableWebSocketBeanName);
+ EnableWebSocket enableWebSocket = AnnotationUtils.findAnnotation(enableWebSocketBean.getClass(), EnableWebSocket.class);
+ assert enableWebSocket != null;
+ if (enableWebSocket.scanBasePackages().length != 0) {
+ basePackages = enableWebSocket.scanBasePackages();
+ break;
+ }
+ }
+ }
+
+ // use @SpringBootApplication package
+ if (basePackages == null) {
+ String[] springBootApplicationBeanName = context.getBeanNamesForAnnotation(SpringBootApplication.class);
+ Object springBootApplicationBean = context.getBean(springBootApplicationBeanName[0]);
+ SpringBootApplication springBootApplication = AnnotationUtils.findAnnotation(springBootApplicationBean.getClass(), SpringBootApplication.class);
+ assert springBootApplication != null;
+ if (springBootApplication.scanBasePackages().length != 0) {
+ basePackages = springBootApplication.scanBasePackages();
+ } else {
+ String packageName = ClassUtils.getPackageName(springBootApplicationBean.getClass().getName());
+ basePackages = new String[1];
+ basePackages[0] = packageName;
+ }
+ }
+
+ EndpointClassPathScanner scanHandle = new EndpointClassPathScanner((BeanDefinitionRegistry) context, false);
+ if (resourceLoader != null) {
+ scanHandle.setResourceLoader(resourceLoader);
+ }
+
+ for (String basePackage : basePackages) {
+ scanHandle.doScan(basePackage);
+ }
+ }
+
+ private void init() {
+ for (Map.Entry entry : addressWebsocketServerMap.entrySet()) {
+ WebsocketServer websocketServer = entry.getValue();
+ try {
+ websocketServer.init();
+ PojoEndpointServer pojoEndpointServer = websocketServer.getPojoEndpointServer();
+ StringJoiner stringJoiner = new StringJoiner(",");
+ pojoEndpointServer.getPathMatcherSet().forEach(pathMatcher -> stringJoiner.add("'" + pathMatcher.getPattern() + "'"));
+ logger.info(String.format("\033[34mNetty WebSocket started on port: %s with context path(s): %s .\033[0m", pojoEndpointServer.getPort(), stringJoiner.toString()));
+ } catch (InterruptedException e) {
+ logger.error(String.format("websocket [%s] init fail", entry.getKey()), e);
+ } catch (SSLException e) {
+ logger.error(String.format("websocket [%s] ssl create fail", entry.getKey()), e);
+
+ }
+ }
+ }
+
+ private void registerEndpoint(Class> endpointClass) {
+ ServerEndpoint annotation = AnnotatedElementUtils.findMergedAnnotation(endpointClass, ServerEndpoint.class);
+ if (annotation == null) {
+ throw new IllegalStateException("missingAnnotation ServerEndpoint");
+ }
+ ServerEndpointConfig serverEndpointConfig = buildConfig(annotation);
+
+ ApplicationContext context = getApplicationContext();
+ PojoMethodMapping pojoMethodMapping = null;
+ try {
+ pojoMethodMapping = newPojoMethodMapping(endpointClass, context);
+ } catch (DeploymentException e) {
+ throw new IllegalStateException("Failed to register ServerEndpointConfig: " + serverEndpointConfig, e);
+ }
+
+ InetSocketAddress inetSocketAddress = new InetSocketAddress(serverEndpointConfig.getHost(), serverEndpointConfig.getPort());
+ String path = resolveAnnotationValue(annotation.value(), String.class, "path");
+
+ WebsocketServer websocketServer = addressWebsocketServerMap.get(inetSocketAddress);
+ if (websocketServer == null) {
+ PojoEndpointServer pojoEndpointServer = new PojoEndpointServer(pojoMethodMapping, serverEndpointConfig, path);
+ websocketServer = new WebsocketServer(pojoEndpointServer, serverEndpointConfig);
+ addressWebsocketServerMap.put(inetSocketAddress, websocketServer);
+ } else {
+ websocketServer.getPojoEndpointServer().addPathPojoMethodMapping(path, pojoMethodMapping);
+ }
+ }
+
+ protected PojoMethodMapping newPojoMethodMapping(Class> endpointClass, ApplicationContext context)
+ throws DeploymentException {
+ PojoMethodMapping pojoMethodMapping;
+ pojoMethodMapping = new PojoMethodMapping(endpointClass, context, beanFactory);
+ return pojoMethodMapping;
+ }
+
+ private ServerEndpointConfig buildConfig(ServerEndpoint annotation) {
+ String host = resolveAnnotationValue(annotation.host(), String.class, "host");
+ int port = resolveAnnotationValue(annotation.port(), Integer.class, "port");
+ String path = resolveAnnotationValue(annotation.value(), String.class, "value");
+ int bossLoopGroupThreads = resolveAnnotationValue(annotation.bossLoopGroupThreads(), Integer.class, "bossLoopGroupThreads");
+ int workerLoopGroupThreads = resolveAnnotationValue(annotation.workerLoopGroupThreads(), Integer.class, "workerLoopGroupThreads");
+ boolean useCompressionHandler = resolveAnnotationValue(annotation.useCompressionHandler(), Boolean.class, "useCompressionHandler");
+
+ int optionConnectTimeoutMillis = resolveAnnotationValue(annotation.optionConnectTimeoutMillis(), Integer.class, "optionConnectTimeoutMillis");
+ int optionSoBacklog = resolveAnnotationValue(annotation.optionSoBacklog(), Integer.class, "optionSoBacklog");
+
+ int childOptionWriteSpinCount = resolveAnnotationValue(annotation.childOptionWriteSpinCount(), Integer.class, "childOptionWriteSpinCount");
+ int childOptionWriteBufferHighWaterMark = resolveAnnotationValue(annotation.childOptionWriteBufferHighWaterMark(), Integer.class, "childOptionWriteBufferHighWaterMark");
+ int childOptionWriteBufferLowWaterMark = resolveAnnotationValue(annotation.childOptionWriteBufferLowWaterMark(), Integer.class, "childOptionWriteBufferLowWaterMark");
+ int childOptionSoRcvbuf = resolveAnnotationValue(annotation.childOptionSoRcvbuf(), Integer.class, "childOptionSoRcvbuf");
+ int childOptionSoSndbuf = resolveAnnotationValue(annotation.childOptionSoSndbuf(), Integer.class, "childOptionSoSndbuf");
+ boolean childOptionTcpNodelay = resolveAnnotationValue(annotation.childOptionTcpNodelay(), Boolean.class, "childOptionTcpNodelay");
+ boolean childOptionSoKeepalive = resolveAnnotationValue(annotation.childOptionSoKeepalive(), Boolean.class, "childOptionSoKeepalive");
+ int childOptionSoLinger = resolveAnnotationValue(annotation.childOptionSoLinger(), Integer.class, "childOptionSoLinger");
+ boolean childOptionAllowHalfClosure = resolveAnnotationValue(annotation.childOptionAllowHalfClosure(), Boolean.class, "childOptionAllowHalfClosure");
+
+ int readerIdleTimeSeconds = resolveAnnotationValue(annotation.readerIdleTimeSeconds(), Integer.class, "readerIdleTimeSeconds");
+ int writerIdleTimeSeconds = resolveAnnotationValue(annotation.writerIdleTimeSeconds(), Integer.class, "writerIdleTimeSeconds");
+ int allIdleTimeSeconds = resolveAnnotationValue(annotation.allIdleTimeSeconds(), Integer.class, "allIdleTimeSeconds");
+
+ int maxFramePayloadLength = resolveAnnotationValue(annotation.maxFramePayloadLength(), Integer.class, "maxFramePayloadLength");
+
+ boolean useEventExecutorGroup = resolveAnnotationValue(annotation.useEventExecutorGroup(), Boolean.class, "useEventExecutorGroup");
+ int eventExecutorGroupThreads = resolveAnnotationValue(annotation.eventExecutorGroupThreads(), Integer.class, "eventExecutorGroupThreads");
+
+ String sslKeyPassword = resolveAnnotationValue(annotation.sslKeyPassword(), String.class, "sslKeyPassword");
+ String sslKeyStore = resolveAnnotationValue(annotation.sslKeyStore(), String.class, "sslKeyStore");
+ String sslKeyStorePassword = resolveAnnotationValue(annotation.sslKeyStorePassword(), String.class, "sslKeyStorePassword");
+ String sslKeyStoreType = resolveAnnotationValue(annotation.sslKeyStoreType(), String.class, "sslKeyStoreType");
+ String sslTrustStore = resolveAnnotationValue(annotation.sslTrustStore(), String.class, "sslTrustStore");
+ String sslTrustStorePassword = resolveAnnotationValue(annotation.sslTrustStorePassword(), String.class, "sslTrustStorePassword");
+ String sslTrustStoreType = resolveAnnotationValue(annotation.sslTrustStoreType(), String.class, "sslTrustStoreType");
+
+ String[] corsOrigins = annotation.corsOrigins();
+ if (corsOrigins.length != 0) {
+ for (int i = 0; i < corsOrigins.length; i++) {
+ corsOrigins[i] = resolveAnnotationValue(corsOrigins[i], String.class, "corsOrigins");
+ }
+ }
+ Boolean corsAllowCredentials = resolveAnnotationValue(annotation.corsAllowCredentials(), Boolean.class, "corsAllowCredentials");
+
+ ServerEndpointConfig serverEndpointConfig = new ServerEndpointConfig(host, port, bossLoopGroupThreads, workerLoopGroupThreads
+ , useCompressionHandler, optionConnectTimeoutMillis, optionSoBacklog, childOptionWriteSpinCount, childOptionWriteBufferHighWaterMark
+ , childOptionWriteBufferLowWaterMark, childOptionSoRcvbuf, childOptionSoSndbuf, childOptionTcpNodelay, childOptionSoKeepalive
+ , childOptionSoLinger, childOptionAllowHalfClosure, readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds
+ , maxFramePayloadLength, useEventExecutorGroup, eventExecutorGroupThreads
+ , sslKeyPassword, sslKeyStore, sslKeyStorePassword, sslKeyStoreType
+ , sslTrustStore, sslTrustStorePassword, sslTrustStoreType
+ , corsOrigins, corsAllowCredentials);
+
+ return serverEndpointConfig;
+ }
+
+ private T resolveAnnotationValue(Object value, Class requiredType, String paramName) {
+ if (value == null) {
+ return null;
+ }
+ TypeConverter typeConverter = beanFactory.getTypeConverter();
+
+ if (value instanceof String) {
+ String strVal = beanFactory.resolveEmbeddedValue((String) value);
+ BeanExpressionResolver beanExpressionResolver = beanFactory.getBeanExpressionResolver();
+ if (beanExpressionResolver != null) {
+ value = beanExpressionResolver.evaluate(strVal, new BeanExpressionContext(beanFactory, null));
+ } else {
+ value = strVal;
+ }
+ }
+ try {
+ return typeConverter.convertIfNecessary(value, requiredType);
+ } catch (TypeMismatchException e) {
+ throw new IllegalArgumentException("Failed to convert value of parameter '" + paramName + "' to required type '" + requiredType.getName() + "'");
+ }
+ }
+
+ @Override
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+}
--
Gitee
From caf0e4669bedc4f281c1e41255b5bde5f68f531c Mon Sep 17 00:00:00 2001
From: giant <553954594@qq.com>
Date: Sat, 11 Jan 2025 20:35:21 +0800
Subject: [PATCH 2/8] =?UTF-8?q?=E4=BC=98=E5=8C=96io=EF=BC=8C@OnBinary?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A0=86=E5=A4=96=E5=86=85=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../DirectBuffMethodArgumentResolver.java | 29 +++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 src/main/java/org/yeauty/support/DirectBuffMethodArgumentResolver.java
diff --git a/src/main/java/org/yeauty/support/DirectBuffMethodArgumentResolver.java b/src/main/java/org/yeauty/support/DirectBuffMethodArgumentResolver.java
new file mode 100644
index 0000000..aed198e
--- /dev/null
+++ b/src/main/java/org/yeauty/support/DirectBuffMethodArgumentResolver.java
@@ -0,0 +1,29 @@
+package org.yeauty.support;
+import org.springframework.core.MethodParameter;
+import org.yeauty.annotation.OnBinary;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.Channel;
+import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
+
+/**
+ * 支持使用直接内存,ByteMethodArgumentResolver将堆外内存加载到堆内存了,对cpu和内存不友好
+ * @author giant
+ *
+ */
+public class DirectBuffMethodArgumentResolver implements MethodArgumentResolver {
+
+ @Override
+ public boolean supportsParameter(MethodParameter parameter) {
+ // TODO Auto-generated method stub
+ return parameter.getMethod().isAnnotationPresent(OnBinary.class) &¶meter.getParameterType().equals(ByteBuf.class);
+ }
+
+ @Override
+ public Object resolveArgument(MethodParameter parameter, Channel channel, Object object) throws Exception {
+ // 解析参数的逻辑
+ BinaryWebSocketFrame binaryWebSocketFrame = (BinaryWebSocketFrame) object;//netty默认是直接内存
+ ByteBuf content = binaryWebSocketFrame.content();
+ return content;
+ }
+}
\ No newline at end of file
--
Gitee
From 4aa175b1e61cff58ed559373ec7e2ae3c37ddc81 Mon Sep 17 00:00:00 2001
From: giant <553954594@qq.com>
Date: Sat, 11 Jan 2025 20:39:51 +0800
Subject: [PATCH 3/8] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B3=A8=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/yeauty/standard/ServerEndpointExporter.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/main/java/org/yeauty/standard/ServerEndpointExporter.java b/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
index 90682bb..d99f892 100755
--- a/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
+++ b/src/main/java/org/yeauty/standard/ServerEndpointExporter.java
@@ -166,6 +166,13 @@ public class ServerEndpointExporter extends ApplicationObjectSupport implements
}
}
+ /**
+ * 可集成重写,支持自定义PojoMethodMapping
+ * @param endpointClass
+ * @param context
+ * @return
+ * @throws DeploymentException
+ */
protected PojoMethodMapping newPojoMethodMapping(Class> endpointClass, ApplicationContext context)
throws DeploymentException {
PojoMethodMapping pojoMethodMapping;
--
Gitee
From b64a60ee853cd96d1f44eeff963ef04cc921481f Mon Sep 17 00:00:00 2001
From: giant <553954594@qq.com>
Date: Sat, 11 Jan 2025 23:02:23 +0800
Subject: [PATCH 4/8] =?UTF-8?q?netty=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E7=94=A8=E7=9B=B4=E6=8E=A5=E5=86=85=E5=AD=98=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 2 +-
.../org/yeauty/pojo/PojoMethodMapping.java | 3 ++-
src/main/java/org/yeauty/util/FileUtils.java | 25 +++++++++++++++++++
3 files changed, 28 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/org/yeauty/util/FileUtils.java
diff --git a/pom.xml b/pom.xml
index 4825fc2..e0aad80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,7 +36,7 @@
- 4.1.67.Final
+ 4.1.116.Final
2.0.0.RELEASE
diff --git a/src/main/java/org/yeauty/pojo/PojoMethodMapping.java b/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
index 841e8e9..8f814a8 100755
--- a/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
+++ b/src/main/java/org/yeauty/pojo/PojoMethodMapping.java
@@ -340,7 +340,7 @@ public class PojoMethodMapping {
return methodArgumentResolvers;
}
- protected List getDefaultResolvers() {
+ protected List getDefaultResolvers() {//可继承,重写
List resolvers = new ArrayList<>();
resolvers.add(new SessionMethodArgumentResolver());
resolvers.add(new HttpHeadersMethodArgumentResolver());
@@ -352,6 +352,7 @@ public class PojoMethodMapping {
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
resolvers.add(new EventMethodArgumentResolver(beanFactory));
+ resolvers.add(new DirectBuffMethodArgumentResolver());//支持对外内存
return resolvers;
}
diff --git a/src/main/java/org/yeauty/util/FileUtils.java b/src/main/java/org/yeauty/util/FileUtils.java
new file mode 100644
index 0000000..642012f
--- /dev/null
+++ b/src/main/java/org/yeauty/util/FileUtils.java
@@ -0,0 +1,25 @@
+package org.yeauty.util;
+
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+import io.netty.buffer.ByteBuf;
+
+public class FileUtils {
+
+ /**
+ * 直接内存直接写文件
+ * @param byteBuf
+ * @param filePath
+ * @throws Exception
+ */
+ public static void writeByteBufToFile(ByteBuf byteBuf, String filePath) throws Exception {
+ // 创建一个临时的CompositeByteBuf,并写入文件
+ try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw");
+ FileChannel fileChannel = raf.getChannel()) {
+ byteBuf.readBytes(fileChannel, byteBuf.readerIndex(), byteBuf.readableBytes());
+// fileChannel.write(byteBuf.nioBuffer());
+ byteBuf.release();
+ }
+ }
+}
--
Gitee
From 4a4e90be6a9e74b9077cb01facc35d269cd74174 Mon Sep 17 00:00:00 2001
From: giant <553954594@qq.com>
Date: Sun, 26 Jan 2025 13:21:58 +0800
Subject: [PATCH 5/8] =?UTF-8?q?onMessage=E6=94=AF=E6=8C=81@PathVariable?=
=?UTF-8?q?=E6=B3=A8=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 7 +-
.../org/yeauty/pojo/PojoEndpointServer.java | 528 +++++++++---------
.../org/yeauty/pojo/PojoMethodMapping.java | 10 +-
.../standard/WebSocketServerHandler.java | 157 ++++--
...ava => ByteBufMethodArgumentResolver.java} | 16 +-
.../ChannelMethodArgumentResolver.java | 29 +
src/main/java/org/yeauty/util/FileUtils.java | 23 +-
7 files changed, 445 insertions(+), 325 deletions(-)
rename src/main/java/org/yeauty/support/{DirectBuffMethodArgumentResolver.java => ByteBufMethodArgumentResolver.java} (68%)
create mode 100644 src/main/java/org/yeauty/support/ChannelMethodArgumentResolver.java
diff --git a/pom.xml b/pom.xml
index e0aad80..97d9de5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,7 @@
4.1.116.Final
- 2.0.0.RELEASE
+ 2.3.12.RELEASE
@@ -58,6 +58,11 @@
netty-handler
${netty.version}
+
+ javax.servlet
+ javax.servlet-api
+ 4.0.1
+
diff --git a/src/main/java/org/yeauty/pojo/PojoEndpointServer.java b/src/main/java/org/yeauty/pojo/PojoEndpointServer.java
index f1fd925..92fc6a8 100755
--- a/src/main/java/org/yeauty/pojo/PojoEndpointServer.java
+++ b/src/main/java/org/yeauty/pojo/PojoEndpointServer.java
@@ -1,257 +1,271 @@
-package org.yeauty.pojo;
-
-import io.netty.channel.Channel;
-import io.netty.handler.codec.http.FullHttpRequest;
-import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
-import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
-import io.netty.handler.codec.http.websocketx.WebSocketFrame;
-import io.netty.util.Attribute;
-import io.netty.util.AttributeKey;
-import io.netty.util.internal.logging.InternalLogger;
-import io.netty.util.internal.logging.InternalLoggerFactory;
-import org.springframework.beans.TypeMismatchException;
-import org.yeauty.standard.ServerEndpointConfig;
-import org.yeauty.support.*;
-
-import java.lang.reflect.Method;
-import java.util.*;
-
-/**
- * @author Yeauty
- * @version 1.0
- */
-public class PojoEndpointServer {
-
- private static final AttributeKey