MessageAsmMethodBoost

This commit is contained in:
redkale
2023-12-26 00:16:45 +08:00
parent 498b2ff70f
commit 6db029263c
12 changed files with 341 additions and 62 deletions

View File

@@ -86,6 +86,7 @@ public abstract class AsmMethodBoost<T> {
/**
* 对方法进行动态加强处理
*
* @param classLoader ClassLoader
* @param cw 动态字节码Writer
* @param newDynName 动态新类名
* @param fieldPrefix 动态字段的前缀
@@ -95,16 +96,17 @@ public abstract class AsmMethodBoost<T> {
*
* @return 下一个新的方法名不做任何处理应返回参数newMethodName
*/
public abstract String doMethod(ClassWriter cw, String newDynName, String fieldPrefix,
List<Class<? extends Annotation>> filterAnns, Method method, @Nullable String newMethodName);
public abstract String doMethod(ClassLoader classLoader, ClassWriter cw, String newDynName,
String fieldPrefix, List<Class<? extends Annotation>> filterAnns, Method method, @Nullable String newMethodName);
/** 处理所有动态方法后调用
*
* @param classLoader ClassLoader
* @param cw 动态字节码Writer
* @param newDynName 动态新类名
* @param fieldPrefix 动态字段的前缀
*/
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) {
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
}
/**
@@ -274,22 +276,22 @@ public abstract class AsmMethodBoost<T> {
}
@Override
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix,
public String doMethod(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix,
List<Class<? extends Annotation>> filterAnns, Method method, String newMethodName) {
String newName = newMethodName;
for (AsmMethodBoost item : items) {
if (item != null) {
newName = item.doMethod(cw, newDynName, fieldPrefix, filterAnns, method, newName);
newName = item.doMethod(classLoader, cw, newDynName, fieldPrefix, filterAnns, method, newName);
}
}
return newName;
}
@Override
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) {
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
for (AsmMethodBoost item : items) {
if (item != null) {
item.doAfterMethods(cw, newDynName, fieldPrefix);
item.doAfterMethods(classLoader, cw, newDynName, fieldPrefix);
}
}
}

View File

@@ -165,4 +165,23 @@ public final class Asms {
}
}
public static void visitPrimitiveVirtual(MethodVisitor mv, Class clazz) {
if (clazz == boolean.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
} else if (clazz == byte.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
} else if (clazz == short.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
} else if (clazz == char.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
} else if (clazz == int.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
} else if (clazz == float.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
} else if (clazz == long.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
} else if (clazz == double.class) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
}
}
}

View File

@@ -53,7 +53,8 @@ public class CacheAsmMethodBoost extends AsmMethodBoost {
}
@Override
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
public String doMethod(ClassLoader classLoader, ClassWriter cw,
String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
Map<String, CacheAction> actions = this.actionMap;
if (actions == null) {
actions = new LinkedHashMap<>();
@@ -134,8 +135,8 @@ public class CacheAsmMethodBoost extends AsmMethodBoost {
}
mv.visitInsn(AASTORE);
}
mv.visitMethodInsn(INVOKEVIRTUAL, CacheAction.class.getName().replace('.', '/'), "get", "(Lorg/redkale/util/ThrowSupplier;[Ljava/lang/Object;)Ljava/lang/Object;", false);
String throwFuncDesc = Type.getDescriptor(ThrowSupplier.class);
mv.visitMethodInsn(INVOKEVIRTUAL, CacheAction.class.getName().replace('.', '/'), "get", "(" + throwFuncDesc + "[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(CHECKCAST, method.getReturnType().getName().replace('.', '/'));
mv.visitInsn(ARETURN);
Label l2 = new Label();

View File

@@ -38,7 +38,8 @@ public class LockAsmMethodBoost extends AsmMethodBoost {
}
@Override
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
public String doMethod(ClassLoader classLoader, ClassWriter cw,
String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
Locked locked = method.getAnnotation(Locked.class);
if (locked == null) {
return newMethodName;
@@ -77,7 +78,7 @@ public class LockAsmMethodBoost extends AsmMethodBoost {
}
@Override
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) {
public void doAfterMethods(ClassLoader classLoader, ClassWriter cw, String newDynName, String fieldPrefix) {
//do nothing
}

View File

@@ -5,6 +5,7 @@ package org.redkale.mq.spi;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -16,6 +17,7 @@ import org.redkale.mq.MessageConsumer;
*
* @author zhangjx
*/
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)
@@ -24,6 +26,7 @@ public @interface DynForMessage {
Class<? extends MessageConsumer> value();
@Inherited
@Documented
@Target({TYPE})
@Retention(RUNTIME)

View File

@@ -167,6 +167,9 @@ public abstract class MessageAgent implements MessageManager {
if (loginfo.length() > 0) {
logger.log(Level.INFO, loginfo.toString());
}
if (application.isCompileMode()) {
return;
}
//----------------- MessageClient -----------------
if (this.httpRpcClient != null || !this.httpMessageClient.isEmpty()) {
this.httpMessageClient.putMessageRespProcessor();

View File

@@ -7,14 +7,50 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.redkale.asm.AnnotationVisitor;
import org.redkale.asm.AsmMethodBean;
import org.redkale.asm.AsmMethodBoost;
import org.redkale.asm.Asms;
import org.redkale.asm.ClassWriter;
import static org.redkale.asm.ClassWriter.COMPUTE_FRAMES;
import org.redkale.asm.FieldVisitor;
import org.redkale.asm.Label;
import org.redkale.asm.MethodVisitor;
import org.redkale.asm.Opcodes;
import static org.redkale.asm.Opcodes.ACC_BRIDGE;
import static org.redkale.asm.Opcodes.ACC_PRIVATE;
import static org.redkale.asm.Opcodes.ACC_PUBLIC;
import static org.redkale.asm.Opcodes.ACC_STATIC;
import static org.redkale.asm.Opcodes.ACC_SUPER;
import static org.redkale.asm.Opcodes.ACC_SYNTHETIC;
import static org.redkale.asm.Opcodes.ALOAD;
import static org.redkale.asm.Opcodes.ASTORE;
import static org.redkale.asm.Opcodes.ATHROW;
import static org.redkale.asm.Opcodes.CHECKCAST;
import static org.redkale.asm.Opcodes.DUP;
import static org.redkale.asm.Opcodes.GETFIELD;
import static org.redkale.asm.Opcodes.GOTO;
import static org.redkale.asm.Opcodes.INVOKESPECIAL;
import static org.redkale.asm.Opcodes.INVOKEVIRTUAL;
import static org.redkale.asm.Opcodes.NEW;
import static org.redkale.asm.Opcodes.POP;
import static org.redkale.asm.Opcodes.PUTFIELD;
import static org.redkale.asm.Opcodes.RETURN;
import static org.redkale.asm.Opcodes.V11;
import org.redkale.convert.ConvertFactory;
import org.redkale.inject.ResourceFactory;
import org.redkale.mq.MessageConext;
import org.redkale.mq.MessageConsumer;
import org.redkale.mq.Messaged;
import org.redkale.mq.ResourceConsumer;
import org.redkale.util.RedkaleClassLoader;
import org.redkale.util.RedkaleException;
import org.redkale.util.TypeToken;
import org.redkale.util.Utility;
/**
*
@@ -24,8 +60,19 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Messaged.class);
public MessageAsmMethodBoost(boolean remote, Class serviceType) {
private final AtomicInteger index = new AtomicInteger();
private final MessageModuleEngine messageEngine;
private Map<String, AsmMethodBean> methodBeans;
private RedkaleClassLoader.DynBytesClassLoader newLoader;
private List<Class<? extends MessageConsumer>> consumers;
public MessageAsmMethodBoost(boolean remote, Class serviceType, MessageModuleEngine messageEngine) {
super(remote, serviceType);
this.messageEngine = messageEngine;
}
@Override
@@ -34,7 +81,8 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
}
@Override
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, String newMethodName) {
public String doMethod(ClassLoader classLoader, ClassWriter cw,
String newDynName, String fieldPrefix, List filterAnns, Method method, String newMethodName) {
if (serviceType.getAnnotation(DynForMessage.class) != null) {
return newMethodName;
}
@@ -72,11 +120,180 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
}
ConvertFactory factory = ConvertFactory.findConvert(messaged.convertType()).getFactory();
factory.loadDecoder(messageType);
if (newLoader == null) {
newLoader = new RedkaleClassLoader.DynBytesClassLoader(classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader);
}
createInnerConsumer(cw, method, paramKind, TypeToken.typeToClass(messageType), messaged, newDynName, newMethodName);
return newMethodName;
}
//paramKind: 1:单个MessageType; 2: MessageConext & MessageType; 3: MessageType & MessageConext;
private void createInnerConsumer(ClassWriter parentCW, Method method, int paramKind,
Class msgType, Messaged messaged, String newDynName, String newMethodName) {
final String newDynDesc = "L" + newDynName + ";";
final String innerClassName = "Dyn" + MessageConsumer.class.getSimpleName() + index.incrementAndGet();
final String innerFullName = newDynName + "$" + innerClassName;
final String msgTypeDesc = org.redkale.asm.Type.getDescriptor(TypeToken.primitiveToWrapper(msgType));
final String messageConsumerName = MessageConsumer.class.getName().replace('.', '/');
final String messageConsumerDesc = org.redkale.asm.Type.getDescriptor(MessageConsumer.class);
final String messageConextDesc = org.redkale.asm.Type.getDescriptor(MessageConext.class);
final boolean throwFlag = Utility.contains(method.getExceptionTypes(), e -> !RuntimeException.class.isAssignableFrom(e));
if (methodBeans == null) {
methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
}
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
String genericMsgTypeDesc = msgTypeDesc;
if (!msgType.isPrimitive()) {
String methodSignature = methodBean.getSignature().replace(messageConextDesc, "");
genericMsgTypeDesc = methodSignature.substring(1, methodSignature.lastIndexOf(')')); //获取()中的值
}
parentCW.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC);
MethodVisitor mv;
ClassWriter cw = new ClassWriter(COMPUTE_FRAMES);
//
cw.visit(V11, ACC_PUBLIC + ACC_SUPER, innerFullName, "Ljava/lang/Object;" + messageConsumerDesc.replace(";", "<" + genericMsgTypeDesc + ">;"),
"java/lang/Object", new String[]{messageConsumerName});
{
AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(ResourceConsumer.class), true);
Asms.visitAnnotation(av, messaged);
av.visitEnd();
}
cw.visitInnerClass(innerFullName, newDynName, innerClassName, ACC_PUBLIC + ACC_STATIC);
{
FieldVisitor fv = cw.visitField(ACC_PRIVATE, "service", newDynDesc, null, null);
fv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(" + newDynDesc + ")V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, innerFullName, "service", newDynDesc);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitInsn(RETURN);
Label l3 = new Label();
mv.visitLabel(l3);
mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l3, 0);
mv.visitLocalVariable("service", newDynDesc, null, l0, l3, 1);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
String methodName = newMethodName == null ? method.getName() : newMethodName;
mv = cw.visitMethod(ACC_PUBLIC, "onMessage", "(" + messageConextDesc + msgTypeDesc + ")V",
msgTypeDesc.equals(genericMsgTypeDesc) ? null : ("(" + messageConextDesc + genericMsgTypeDesc + ")V"), null);
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
if (throwFlag) {
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");
mv.visitLabel(l0);
}
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, innerFullName, "service", newDynDesc);
if (paramKind == 1) { //1: 单个MessageType;
mv.visitVarInsn(ALOAD, 2);
Asms.visitPrimitiveVirtual(mv, msgType);
} else if (paramKind == 2) { //2: MessageConext & MessageType;
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
Asms.visitPrimitiveVirtual(mv, msgType);
} else { //3: MessageType & MessageConext;
mv.visitVarInsn(ALOAD, 2);
Asms.visitPrimitiveVirtual(mv, msgType);
mv.visitVarInsn(ALOAD, 1);
}
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, methodName, org.redkale.asm.Type.getMethodDescriptor(method), false);
if (method.getReturnType() != void.class) {
mv.visitInsn(POP);
}
mv.visitLabel(l1);
Label l3 = null, l4 = null;
if (throwFlag) {
l3 = new Label();
mv.visitJumpInsn(GOTO, l3);
mv.visitLabel(l2);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{"java/lang/Throwable"});
mv.visitVarInsn(ASTORE, 3);
l4 = new Label();
mv.visitLabel(l4);
mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V", false);
mv.visitInsn(ATHROW);
mv.visitLabel(l3);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
}
mv.visitInsn(RETURN);
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLocalVariable("this", "L" + innerFullName + ";", null, l0, l5, 0);
mv.visitLocalVariable("context", messageConextDesc, null, l0, l5, 1);
mv.visitLocalVariable("message", msgTypeDesc, msgTypeDesc.equals(genericMsgTypeDesc) ? null : genericMsgTypeDesc, l0, l5, 2);
if (throwFlag) {
mv.visitLocalVariable("e", "Ljava/lang/Throwable;", null, l4, l3, 3);
}
mv.visitMaxs(4, 4);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "onMessage", "(" + messageConextDesc + "Ljava/lang/Object;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, "java/lang/String");
mv.visitMethodInsn(INVOKEVIRTUAL, innerFullName, "onMessage", "(" + messageConextDesc + msgTypeDesc + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
Class cz = newLoader.loadClass((innerFullName).replace('/', '.'), bytes);
if (consumers == null) {
consumers = new ArrayList<>();
}
consumers.add(cz);
RedkaleClassLoader.putDynClass((innerFullName).replace('/', '.'), bytes, cz);
}
@Override
public void doInstance(ResourceFactory resourceFactory, Object service) {
DynForMessage[] dyns = service.getClass().getAnnotationsByType(DynForMessage.class);
if (dyns.length < 1) {
return;
}
try {
if (Utility.isNotEmpty(consumers)) {
for (Class<? extends MessageConsumer> clazz : consumers) {
MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service);
messageEngine.addMessageConsumer(consumer);
}
} else {
for (DynForMessage item : dyns) {
Class<? extends MessageConsumer> clazz = item.value();
MessageConsumer consumer = (MessageConsumer) clazz.getConstructors()[0].newInstance(service);
messageEngine.addMessageConsumer(consumer);
}
}
} catch (Exception e) {
throw new RedkaleException(e);
}
}
}

View File

@@ -17,6 +17,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import org.redkale.asm.AsmMethodBoost;
import org.redkale.boot.Application;
import org.redkale.boot.ClassFilter;
import org.redkale.boot.ModuleEngine;
@@ -59,6 +60,23 @@ public class MessageModuleEngine extends ModuleEngine {
super(application);
}
/**
* 动态扩展类的方法
*
* @param remote 是否远程模式
* @param serviceClass 类
*
* @return 方法动态扩展器
*/
public AsmMethodBoost createAsmMethodBoost(boolean remote, Class serviceClass) {
return new MessageAsmMethodBoost(remote, serviceClass, this);
}
void addMessageConsumer(MessageConsumer consumer) {
String agentName = consumer.getClass().getAnnotation(ResourceConsumer.class).mq();
agentConsumers.computeIfAbsent(agentName, v -> new CopyOnWriteArrayList<>()).add(consumer);
}
/**
* 判断模块的配置项合并策略, 返回null表示模块不识别此配置项
*
@@ -205,10 +223,17 @@ public class MessageModuleEngine extends ModuleEngine {
}
long s = System.currentTimeMillis();
for (MessageAgent agent : this.messageAgents) {
this.resourceFactory.inject(agent);
agent.init(agent.getConfig());
this.resourceFactory.register(agent.getName(), MessageManager.class, agent);
this.resourceFactory.register(agent.getName(), MessageAgent.class, agent);
String agentName = agent.getConfig().getValue("name", "");
if (!application.isCompileMode()) {
this.resourceFactory.inject(agent);
agent.init(agent.getConfig());
agentName = agent.getName();
} else {
agent.name = agentName;
agent.application = application;
}
this.resourceFactory.register(agentName, MessageManager.class, agent);
this.resourceFactory.register(agentName, MessageAgent.class, agent);
}
logger.info("MessageAgent init in " + (System.currentTimeMillis() - s) + " ms");
}
@@ -409,7 +434,9 @@ public class MessageModuleEngine extends ModuleEngine {
long s = System.currentTimeMillis();
for (MessageAgent agent : this.messageAgents) {
names.add(agent.getName());
agent.stop();
if (!application.isCompileMode()) {
agent.stop();
}
}
logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") stop in " + (System.currentTimeMillis() - s) + " ms");
}
@@ -427,7 +454,9 @@ public class MessageModuleEngine extends ModuleEngine {
long s = System.currentTimeMillis();
for (MessageAgent agent : this.messageAgents) {
names.add(agent.getName());
agent.destroy(agent.getConfig());
if (!application.isCompileMode()) {
agent.destroy(agent.getConfig());
}
}
logger.info("MessageAgent(names=" + JsonConvert.root().convertTo(names) + ") destroy in " + (System.currentTimeMillis() - s) + " ms");
}

View File

@@ -5,7 +5,6 @@
*/
package org.redkale.net.http;
import org.redkale.mq.spi.MessageAgent;
import java.io.*;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.TYPE;
@@ -24,12 +23,13 @@ import org.redkale.asm.Type;
import org.redkale.convert.*;
import org.redkale.convert.json.*;
import org.redkale.inject.ResourceFactory;
import org.redkale.mq.*;
import org.redkale.mq.spi.MessageAgent;
import org.redkale.net.*;
import org.redkale.net.sncp.Sncp;
import org.redkale.service.*;
import org.redkale.source.Flipper;
import org.redkale.util.*;
import org.redkale.util.RedkaleClassLoader.DynBytesClassLoader;
import static org.redkale.util.Utility.isEmpty;
/**
@@ -612,7 +612,7 @@ public final class Rest {
mv.visitEnd();
}
RestClassLoader newLoader = new RestClassLoader(loader);
DynBytesClassLoader newLoader = new DynBytesClassLoader(loader);
Map<String, Annotation[]> msgclassToAnnotations = new HashMap<>();
for (int i = 0; i < messageMethods.size(); i++) { // _DyncXXXWebSocketMessage 子消息List
final Method method = messageMethods.get(i);
@@ -1608,6 +1608,7 @@ public final class Rest {
final String defModuleName = getWebModuleNameLowerCase(serviceType);
final String bigModuleName = getWebModuleName(serviceType);
final String catalog = controller == null ? "" : controller.catalog();
final String httpDesc = Type.getDescriptor(HttpServlet.class);
if (!checkName(catalog)) {
throw new RestException(serviceType.getName() + " have illegal " + RestService.class.getSimpleName() + ".catalog, only 0-9 a-z A-Z _ cannot begin 0-9");
}
@@ -1725,7 +1726,7 @@ public final class Rest {
return null; //没有可HttpMapping的方法
}
Collections.sort(entrys);
RestClassLoader newLoader = new RestClassLoader(loader);
DynBytesClassLoader newLoader = new DynBytesClassLoader(loader);
final int moduleid = controller == null ? 0 : controller.moduleid();
{ //注入 @WebServlet 注解
String urlpath = "";
@@ -3391,7 +3392,7 @@ public final class Rest {
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, newDynName + "$" + entry.newActionClassName, "<init>", "(L" + newDynName + ";)V", false);
mv.visitMethodInsn(INVOKESPECIAL, actionEntryName, "<init>", "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZZILorg/redkale/net/http/HttpServlet;)V", false);
mv.visitMethodInsn(INVOKESPECIAL, actionEntryName, "<init>", "(IILjava/lang/String;[Ljava/lang/String;Ljava/lang/reflect/Method;ZZI" + httpDesc + ")V", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/HashMap", "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(POP);
}
@@ -3477,7 +3478,7 @@ public final class Rest {
try {
RedkaleClassLoader.putDynClass(n, bs, newLoader.findClass(n));
RedkaleClassLoader.putReflectionClass(n);
} catch (ClassNotFoundException e) {
} catch (Exception e) {
throw new RestException(e);
}
});
@@ -3626,32 +3627,6 @@ public final class Rest {
return true;
}
private static class RestClassLoader extends ClassLoader {
private final Map<String, byte[]> classes = new HashMap<>();
public RestClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = classes.get(name);
if (classData == null) {
return super.findClass(name);
}
return super.defineClass(name, classData, 0, classData.length);
}
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
public final void addClass(String name, byte[] b) {
classes.put(name, b);
}
}
private static class MappingEntry implements Comparable<MappingEntry> {
private static final RestMapping DEFAULT__MAPPING;

View File

@@ -552,8 +552,8 @@ public abstract class Sncp {
mv.visitEnd();
}
if (methodBoost != null) {
createNewMethods(serviceImplClass, methodBoost, new HashSet<>(), cw, newDynName, supDynName);
methodBoost.doAfterMethods(cw, newDynName, FIELDPREFIX);
createNewMethods(classLoader, serviceImplClass, methodBoost, new HashSet<>(), cw, newDynName, supDynName);
methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX);
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();
@@ -581,7 +581,8 @@ public abstract class Sncp {
return createLocalService(null, "", serviceImplClass, null, resourceFactory, null, null, null, null, null);
}
private static void createNewMethods(Class clazz, final AsmMethodBoost methodBoost, Set<String> methodKeys, ClassWriter cw, String newDynName, String supDynName) {
private static void createNewMethods(ClassLoader classLoader, Class clazz,
final AsmMethodBoost methodBoost, Set<String> methodKeys, ClassWriter cw, String newDynName, String supDynName) {
if (methodBoost == null) {
return;
}
@@ -596,7 +597,7 @@ public abstract class Sncp {
}
methodKeys.add(mk);
List<Class<? extends Annotation>> filterAnns = methodBoost.filterMethodAnnotations(method);
String newMethodName = methodBoost.doMethod(cw, newDynName, FIELDPREFIX, filterAnns, method, null);
String newMethodName = methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null);
if (newMethodName != null) {
String desc = Type.getMethodDescriptor(method);
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
@@ -995,7 +996,7 @@ public abstract class Sncp {
String newMethodName = null;
if (methodBoost != null) {
List<Class<? extends Annotation>> filterAnns = methodBoost.filterMethodAnnotations(method);
newMethodName = methodBoost.doMethod(cw, newDynName, FIELDPREFIX, filterAnns, method, null);
newMethodName = methodBoost.doMethod(classLoader, cw, newDynName, FIELDPREFIX, filterAnns, method, null);
}
if (newMethodName != null) {
acc = ACC_PRIVATE;
@@ -1097,8 +1098,8 @@ public abstract class Sncp {
mv.visitEnd();
}
if (methodBoost != null) {
createNewMethods(serviceTypeOrImplClass, methodBoost, methodKeys, cw, newDynName, supDynName);
methodBoost.doAfterMethods(cw, newDynName, FIELDPREFIX);
createNewMethods(classLoader, serviceTypeOrImplClass, methodBoost, methodKeys, cw, newDynName, supDynName);
methodBoost.doAfterMethods(classLoader, cw, newDynName, FIELDPREFIX);
}
cw.visitEnd();
byte[] bytes = cw.toByteArray();

View File

@@ -467,6 +467,7 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
final String responseName = SncpResponse.class.getName().replace('.', '/');
final String requestDesc = Type.getDescriptor(SncpRequest.class);
final String responseDesc = Type.getDescriptor(SncpResponse.class);
final String serviceDesc = Type.getDescriptor(Service.class);
final boolean boolReturnTypeFuture = Future.class.isAssignableFrom(method.getReturnType());
final String newDynName = "org/redkaledyn/sncp/servlet/action/_DynSncpActionServlet__" + resourceType.getSimpleName() + "_" + method.getName() + "_" + actionid;
@@ -488,7 +489,7 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
cw.visit(V11, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, newDynName, null, supDynName, null);
{
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;Ljava/lang/Class;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", null, null));
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", null, null));
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
@@ -496,7 +497,7 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
mv.visitVarInsn(ALOAD, 4);
mv.visitVarInsn(ALOAD, 5);
mv.visitVarInsn(ALOAD, 6);
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "(Ljava/lang/String;Ljava/lang/Class;Lorg/redkale/service/Service;" + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", false);
mv.visitMethodInsn(INVOKESPECIAL, supDynName, "<init>", "(Ljava/lang/String;Ljava/lang/Class;" + serviceDesc + uint128Desc + uint128Desc + "Ljava/lang/reflect/Method;)V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(7, 7);
mv.visitEnd();
@@ -608,7 +609,7 @@ public class SncpServlet extends Servlet<SncpContext, SncpRequest, SncpResponse>
}
{ //调用service
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()Lorg/redkale/service/Service;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, newDynName, "service", "()" + serviceDesc, false);
mv.visitTypeInsn(CHECKCAST, serviceImpTypeName);
mv.visitVarInsn(ASTORE, store);

View File

@@ -67,6 +67,7 @@ public class RedkaleClassLoader extends URLClassLoader {
"org.redkale.net.http",
"org.redkale.net.sncp",
"org.redkale.persistence",
"org.redkale.props.spi",
"org.redkale.schedule",
"org.redkale.schedule.spi",
"org.redkale.service",
@@ -564,4 +565,30 @@ public class RedkaleClassLoader extends URLClassLoader {
}
}
}
public static class DynBytesClassLoader extends ClassLoader {
private final Map<String, byte[]> classes = new HashMap<>();
public DynBytesClassLoader(ClassLoader parent) {
super(parent);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
byte[] classData = classes.get(name);
if (classData == null) {
return super.findClass(name);
}
return super.defineClass(name, classData, 0, classData.length);
}
public final Class<?> loadClass(String name, byte[] b) {
return defineClass(name, b, 0, b.length);
}
public final void addClass(String name, byte[] b) {
classes.put(name, b);
}
}
}