diff --git a/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java b/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java index 85c94b9eb..bd0b6a6e1 100644 --- a/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java +++ b/src/main/java/org/redkale/mq/spi/MessageModuleEngine.java @@ -85,9 +85,9 @@ public class MessageModuleEngine extends ModuleEngine { // 在doInstance方法里被调用 void addMessageConsumer(MessageConsumer consumer) { - String mqName = environment.getPropertyValue( - consumer.getClass().getAnnotation(ResourceConsumer.class).mq()); - if (findMessageAgent(mqName) == null) { + ResourceConsumer rc = consumer.getClass().getAnnotation(ResourceConsumer.class); + String mqName = environment.getPropertyValue(rc.mq()); + if (rc.required() && findMessageAgent(mqName) == null) { throw new RedkaleException("Not found " + MessageAgent.class.getSimpleName() + "(name = " + mqName + ") on " + consumer.getClass().getName()); } diff --git a/src/main/java/org/redkale/net/Request.java b/src/main/java/org/redkale/net/Request.java index 854624b58..56dfab458 100644 --- a/src/main/java/org/redkale/net/Request.java +++ b/src/main/java/org/redkale/net/Request.java @@ -6,11 +6,14 @@ package org.redkale.net; import java.io.*; +import java.lang.annotation.Annotation; +import java.lang.reflect.Array; import java.nio.ByteBuffer; import java.util.*; import org.redkale.convert.ConvertDisabled; import org.redkale.convert.bson.BsonConvert; import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Creator; /** * 协议请求对象 @@ -44,6 +47,9 @@ public abstract class Request { protected String traceid; + // Service动态生成接口的方法上的注解 + protected Annotation[] annotations; + protected AsyncConnection channel; /** properties 与 attributes 的区别在于:调用recycle时, attributes会被清空而properties会保留; properties 通常存放需要永久绑定在request里的一些对象 */ @@ -68,6 +74,7 @@ public abstract class Request { this.pipelineCount = request.pipelineCount; this.pipelineCompleted = request.pipelineCompleted; this.traceid = request.traceid; + this.annotations = request.annotations; this.channel = request.channel; } @@ -103,6 +110,7 @@ public abstract class Request { completed = false; keepAlive = false; attributes.clear(); + annotations = null; channel = null; // close it by response } @@ -160,6 +168,38 @@ public abstract class Request { return createTime; } + public Annotation[] getAnnotations() { + if (annotations == null) { + return new Annotation[0]; + } + return Arrays.copyOfRange(annotations, 0, annotations.length); + } + + public T getAnnotation(Class annotationClass) { + if (annotations != null) { + for (Annotation ann : annotations) { + if (ann.annotationType() == annotationClass) { + return annotationClass.cast(ann); + } + } + } + return null; + } + + public T[] getAnnotationsByType(Class annotationClass) { + if (annotations == null) { + return (T[]) Array.newInstance(annotationClass, 0); + } else { + List list = new ArrayList<>(); + for (Annotation ann : annotations) { + if (ann.annotationType() == annotationClass) { + list.add(annotationClass.cast(ann)); + } + } + return list.toArray(Creator.funcArray(annotationClass)); + } + } + /** * @see #getCreateTime() * @return long diff --git a/src/main/java/org/redkale/net/http/HttpRequest.java b/src/main/java/org/redkale/net/http/HttpRequest.java index 49d06e5e5..1f83fc0cb 100644 --- a/src/main/java/org/redkale/net/http/HttpRequest.java +++ b/src/main/java/org/redkale/net/http/HttpRequest.java @@ -315,6 +315,10 @@ public class HttpRequest extends Request { this.keepAlive = keepAlive; } + protected void setAnnotations(Annotation[] annotations) { + this.annotations = annotations; + } + protected ConvertType getRespConvertType() { return this.respConvertType; } diff --git a/src/main/java/org/redkale/net/http/Rest.java b/src/main/java/org/redkale/net/http/Rest.java index d239c969c..36f18c631 100644 --- a/src/main/java/org/redkale/net/http/Rest.java +++ b/src/main/java/org/redkale/net/http/Rest.java @@ -65,13 +65,17 @@ public final class Rest { static final String REST_SERVICE_FIELD_NAME = "_redkale_service"; - static final String REST_SERVICEMAP_FIELD_NAME = - "_redkale_serviceMap"; // 如果只有name=""的Service资源,则实例中_servicemap必须为null + // 如果只有name=""的Service资源,则实例中_servicemap必须为null + static final String REST_SERVICEMAP_FIELD_NAME = "_redkale_serviceMap"; - private static final String REST_PARAMTYPES_FIELD_NAME = - "_redkale_paramTypes"; // 存在泛型的参数数组 Type[][] 第1维度是方法的下标, 第二维度是参数的下标 + // 存在存在方法注解数组 Annotation[][] 第1维度是方法的下标, 第二维度是参数的下标 + private static final String REST_METHOD_ANNS_NAME = "_redkale_methodAnns"; - private static final String REST_RETURNTYPES_FIELD_NAME = "_redkale_returnTypes"; // 存在泛型的结果数组 + // 存在泛型的参数数组 Type[][] 第1维度是方法的下标, 第二维度是参数的下标 + private static final String REST_PARAMTYPES_FIELD_NAME = "_redkale_paramTypes"; + + // 存在泛型的结果数组 + private static final String REST_RETURNTYPES_FIELD_NAME = "_redkale_returnTypes"; private static final java.lang.reflect.Type TYPE_RETRESULT_STRING = new TypeToken>() {}.getType(); @@ -291,6 +295,12 @@ public final class Rest { return "http.resp."; } + // 仅供Rest动态构建里使用 + @ClassDepends + public static void setRequestAnnotations(HttpRequest request, Annotation[] annotations) { + request.setAnnotations(annotations); + } + // 仅供Rest动态构建里 currentUserid() 使用 @ClassDepends public static T orElse(T t, T defValue) { @@ -1306,6 +1316,7 @@ public final class Rest { final Map classMap = new LinkedHashMap<>(); final List entrys = new ArrayList<>(); + final List methodAnns = new ArrayList<>(); final List paramTypes = new ArrayList<>(); final List retvalTypes = new ArrayList<>(); @@ -1352,7 +1363,7 @@ public final class Rest { if (mappings == null) { continue; } - + methodAnns.add(method.getAnnotations()); java.lang.reflect.Type[] ptypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); for (java.lang.reflect.Type t : ptypes) { @@ -1368,6 +1379,7 @@ public final class Rest { + ", serviceType is " + serviceType.getName()); } retvalTypes.add(rtype); + if (mappings.isEmpty()) { // 没有Mapping,设置一个默认值 MappingEntry entry = new MappingEntry( serRpcOnly, @@ -1754,6 +1766,12 @@ public final class Rest { JsonFactory childFactory = createJsonFactory((RestConvert[]) rc[0], (RestConvertCoder[]) rc[1]); genField.set(obj, childFactory.getConvert()); } + Field annsfield = newClazz.getDeclaredField(REST_METHOD_ANNS_NAME); + annsfield.setAccessible(true); + Annotation[][] methodAnnArray = new Annotation[methodAnns.size()][]; + methodAnnArray = methodAnns.toArray(methodAnnArray); + annsfield.set(obj, methodAnnArray); + Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); typesfield.setAccessible(true); java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; @@ -1866,6 +1884,7 @@ public final class Rest { final Map restAttributes = new LinkedHashMap<>(); final Map classMap = new LinkedHashMap<>(); final Map typeRefs = new LinkedHashMap<>(); + final List methodAnns = new ArrayList<>(); final List paramTypes = new ArrayList<>(); final List retvalTypes = new ArrayList<>(); final Map bodyTypes = new HashMap<>(); @@ -1926,6 +1945,7 @@ public final class Rest { } } } + methodAnns.add(method.getAnnotations()); java.lang.reflect.Type[] ptypes = TypeToken.getGenericType(method.getGenericParameterTypes(), serviceType); for (java.lang.reflect.Type t : ptypes) { if (!TypeToken.isClassType(t)) { @@ -2160,6 +2180,19 @@ public final class Rest { mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {serviceTypeInternalName}); mv.visitVarInsn(ASTORE, 3); + // 执行setRequestAnnotations + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, newDynName, REST_METHOD_ANNS_NAME, "[[Ljava/lang/annotation/Annotation;"); + Asms.visitInsn(mv, entry.methodIdx); // 方法下标 + mv.visitInsn(AALOAD); + mv.visitMethodInsn( + INVOKESTATIC, + restInternalName, + "setRequestAnnotations", + "(" + reqDesc + "[Ljava/lang/annotation/Annotation;)V", + false); + final int maxStack = 3 + params.length; List varInsns = new ArrayList<>(); int maxLocals = 4; @@ -4153,6 +4186,17 @@ public final class Rest { fv.visitEnd(); } + { // _methodAnns字段 Annotation[][] + fv = cw.visitField(ACC_PRIVATE, REST_METHOD_ANNS_NAME, "[[Ljava/lang/annotation/Annotation;", null, null); + av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); + StringBuilder sb = new StringBuilder().append('['); + for (Annotation[] rs : methodAnns) { + sb.append(Arrays.toString(rs)).append(','); + } + av0.visit("value", sb.append(']').toString()); + av0.visitEnd(); + fv.visitEnd(); + } { // _paramtypes字段 java.lang.reflect.Type[][] fv = cw.visitField(ACC_PRIVATE, REST_PARAMTYPES_FIELD_NAME, "[[Ljava/lang/reflect/Type;", null, null); av0 = fv.visitAnnotation(Type.getDescriptor(Comment.class), true); @@ -4243,6 +4287,13 @@ public final class Rest { genField.set(obj, childFactory.getConvert()); RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), genField); } + Field annsfield = newClazz.getDeclaredField(REST_METHOD_ANNS_NAME); + annsfield.setAccessible(true); + Annotation[][] methodAnnArray = new Annotation[methodAnns.size()][]; + methodAnnArray = methodAnns.toArray(methodAnnArray); + annsfield.set(obj, methodAnnArray); + RedkaleClassLoader.putReflectionField(newDynName.replace('/', '.'), annsfield); + Field typesfield = newClazz.getDeclaredField(REST_PARAMTYPES_FIELD_NAME); typesfield.setAccessible(true); java.lang.reflect.Type[][] paramtypeArray = new java.lang.reflect.Type[paramTypes.size()][]; diff --git a/src/main/java/org/redkale/util/Inners.java b/src/main/java/org/redkale/util/Inners.java index 698fc63ec..3feabb783 100644 --- a/src/main/java/org/redkale/util/Inners.java +++ b/src/main/java/org/redkale/util/Inners.java @@ -3,8 +3,6 @@ */ package org.redkale.util; -import static org.redkale.asm.Opcodes.*; - import java.io.*; import java.lang.reflect.*; import java.math.*; @@ -16,6 +14,7 @@ import java.util.function.*; import java.util.logging.*; import java.util.stream.Stream; import org.redkale.asm.*; +import static org.redkale.asm.Opcodes.*; /** @author zhangjx */ class Inners { @@ -224,6 +223,9 @@ class Inners { } public static IntFunction createArrayFunction(final Class clazz) { + if (Utility.inNativeImage()) { + return t -> (T[]) Array.newInstance(clazz, t); + } final String interName = clazz.getName().replace('.', '/'); final String interDesc = org.redkale.asm.Type.getDescriptor(clazz); final ClassLoader loader = clazz.getClassLoader();