MessageAsmMethodBoost
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user