diff --git a/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/ArgsValidateResult.java b/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/ArgsValidateResult.java index 8878fd07cc3b9e42a6a2c172d6fd8e7a14076bb9..088dac116e772519e2ce40b3b7acf2dddf491222 100644 --- a/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/ArgsValidateResult.java +++ b/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/ArgsValidateResult.java @@ -22,19 +22,23 @@ package cn.icanci.loopstack.damc.cache; */ public class ArgsValidateResult { /** DAMC 中心的注册地址 例如: 127.0.0.1;127.0.0.1 */ - private String damcCenterAddress; + private java.lang.String damcCenterAddress; /** DAMC 中心的注册port 例如: 9090 */ - private int damcCenterPort; + private int damcCenterPort; /** 被Mock的项目的本地netty服务端口 */ - private int mockedProjectPort; - /** 被Mock的项目的环境值,可选值: QA\UAT\STAGE\STAGE_TEST2 @see EnvEnum */ - private EnvEnum mockedProjectEnv; + private int mockedProjectPort; + /** 被Mock的项目的环境值,可选值: QA\UAT\STAGE\STAGE_TEST2 @see String */ + private String mockedProjectEnv; /** 项目名称 */ - private String mockedProjectName; + private java.lang.String mockedProjectName; /** 项目Code */ - private String mockedProjectCode; + private java.lang.String mockedProjectCode; - public ArgsValidateResult(String damcCenterAddress, int damcCenterPort, int mockedProjectPort, EnvEnum mockedProjectEnv, String mockedProjectName, String mockedProjectCode) { + public ArgsValidateResult() { + } + + public ArgsValidateResult(java.lang.String damcCenterAddress, int damcCenterPort, int mockedProjectPort, String mockedProjectEnv, java.lang.String mockedProjectName, + java.lang.String mockedProjectCode) { this.damcCenterAddress = damcCenterAddress; this.damcCenterPort = damcCenterPort; this.mockedProjectPort = mockedProjectPort; @@ -43,11 +47,11 @@ public class ArgsValidateResult { this.mockedProjectCode = mockedProjectCode; } - public String getDamcCenterAddress() { + public java.lang.String getDamcCenterAddress() { return damcCenterAddress; } - public void setDamcCenterAddress(String damcCenterAddress) { + public void setDamcCenterAddress(java.lang.String damcCenterAddress) { this.damcCenterAddress = damcCenterAddress; } @@ -67,27 +71,27 @@ public class ArgsValidateResult { this.mockedProjectPort = mockedProjectPort; } - public EnvEnum getMockedProjectEnv() { + public String getMockedProjectEnv() { return mockedProjectEnv; } - public void setMockedProjectEnv(EnvEnum mockedProjectEnv) { + public void setMockedProjectEnv(String mockedProjectEnv) { this.mockedProjectEnv = mockedProjectEnv; } - public String getMockedProjectName() { + public java.lang.String getMockedProjectName() { return mockedProjectName; } - public void setMockedProjectName(String mockedProjectName) { + public void setMockedProjectName(java.lang.String mockedProjectName) { this.mockedProjectName = mockedProjectName; } - public String getMockedProjectCode() { + public java.lang.String getMockedProjectCode() { return mockedProjectCode; } - public void setMockedProjectCode(String mockedProjectCode) { + public void setMockedProjectCode(java.lang.String mockedProjectCode) { this.mockedProjectCode = mockedProjectCode; } diff --git a/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/DamcCenterConfigRepository.java b/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/DamcCenterConfigRepository.java index fddf8777abe873f8a0c4a4c9c838bf5b65f81ad5..cfc9c8b326b19585d14781390d8bb3172638318a 100644 --- a/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/DamcCenterConfigRepository.java +++ b/damc-api/damc-api-cache/src/main/java/cn/icanci/loopstack/damc/cache/DamcCenterConfigRepository.java @@ -29,7 +29,7 @@ public class DamcCenterConfigRepository { DamcCenterConfigRepository.argsValidateResult = argsValidateResult; } - public static String getDamcCenterAddress() { + public static java.lang.String getDamcCenterAddress() { return argsValidateResult.getDamcCenterAddress(); } @@ -41,15 +41,15 @@ public class DamcCenterConfigRepository { return argsValidateResult.getMockedProjectPort(); } - public static EnvEnum getMockedProjectEnv() { + public static String getMockedProjectEnv() { return argsValidateResult.getMockedProjectEnv(); } - public static String getMockedProjectName() { + public static java.lang.String getMockedProjectName() { return argsValidateResult.getMockedProjectName(); } - public static String getMockedProjectCode() { + public static java.lang.String getMockedProjectCode() { return argsValidateResult.getMockedProjectCode(); } diff --git a/damc-core/pom.xml b/damc-core/pom.xml index 13013c5ba27a6c9598543567936bcdaf5a17bb0a..d5e842f04ca39449b9b7350bc7e281617d133181 100644 --- a/damc-core/pom.xml +++ b/damc-core/pom.xml @@ -22,16 +22,11 @@ - - org.ow2.asm - asm - ${asm.version} - - - org.ow2.asm - asm-commons - ${asm.version} - + + + + + org.codehaus.groovy groovy-all @@ -89,6 +84,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/DamcCoreStart.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/DamcCoreStart.java index a78261fa2131f712ed8de66a5facc262033529b5..2be8e0b5ce0952e62d893208eb84f2a078c71572 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/DamcCoreStart.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/DamcCoreStart.java @@ -16,6 +16,7 @@ */ package cn.icanci.loopstack.damc.core; +import java.lang.instrument.Instrumentation; import java.util.List; import java.util.concurrent.TimeUnit; @@ -34,10 +35,9 @@ import cn.hutool.json.JSONUtil; import cn.icanci.loopstack.damc.api.groovy.GroovyScriptRepository; import cn.icanci.loopstack.damc.api.http.Client; import cn.icanci.loopstack.damc.api.http.HttpClientImpl; +import cn.icanci.loopstack.damc.cache.ArgsValidateResult; import cn.icanci.loopstack.damc.cache.DamcCenterConfigRepository; -import cn.icanci.loopstack.damc.core.dynamic.AttachTool; -import cn.icanci.loopstack.damc.core.dynamic.ReTransformTrigger; -import cn.icanci.loopstack.damc.core.dynamic.ReTransformTriggerMBean; +import cn.icanci.loopstack.damc.core.dynamic.*; import cn.icanci.loopstack.damc.core.server.RegisterServer; import cn.icanci.loopstack.damc.core.service.MockRunnerService; import cn.icanci.loopstack.damc.spi.model.UriConstant; @@ -60,6 +60,12 @@ public class DamcCoreStart implements ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(DamcCoreStart.class); + public static void setInitParam(ArgsValidateResult result, Instrumentation inst) { + // 初始化到仓储 + DynamicAgent.setInstrumentation(inst); + DynamicAgent.setResult(result); + } + /** * Set the ApplicationContext that this object runs in. * Normally this call will be used to initialize the object. @@ -77,6 +83,10 @@ public class DamcCoreStart implements ApplicationContextAware { @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { try { + // 获取类加载器 + ClassLoader classLoader = this.getClass().getClassLoader(); + System.getProperties().put(DamcCoreConstant.APP_RUNNER_CLASS_LOADER, classLoader.getClass().getName()); + AttachTool.attachAgent(); MockRunnerService.setContext(applicationContext); diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DamcCoreConstant.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DamcCoreConstant.java index 1ef9e6294e782d58407aad76035e42f838e4f6ba..f9ca94930957163257c2f3cc35afb230972ab13c 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DamcCoreConstant.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DamcCoreConstant.java @@ -24,4 +24,5 @@ public interface DamcCoreConstant { String DAMC_ARGS_KEY = "DAMC_ARGS"; String DAMC_ARGS_INIT_KEY = "DAMC_ARGS_INIT"; String DAMC_ARGS_AGENT_PATH_KEY = "DAMC_ARGS_AGENT_PATH"; + String APP_RUNNER_CLASS_LOADER = "APP_RUNNER_CLASS_LOADER"; } diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgent.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgent.java index 86466f486a37c49bb3f43df9da98024d7004c698..0b8af457c9b958b0753ecd151c1fd8e4d41b5536 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgent.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgent.java @@ -18,11 +18,16 @@ package cn.icanci.loopstack.damc.core.dynamic; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.security.ProtectionDomain; +import java.util.Set; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import com.google.common.collect.Sets; + import cn.icanci.loopstack.damc.cache.ArgsValidateResult; import cn.icanci.loopstack.damc.cache.DamcCenterConfigRepository; import cn.icanci.loopstack.damc.cache.EnvEnum; @@ -41,12 +46,12 @@ public class DynamicAgent { * @param args args,例如: 127.0.0.1;127.0.0.2|9191|9292|QA|DAMC测试项目|DAMC-TEST-CORE^/Users/icanci/ideaProjects/loopstack/damc/damc-core/target/damc-core-1.0-SNAPSHOT-jar-with-dependencies.jar * @param inst inst */ - public static void premain(String args, Instrumentation inst) { + public static void premain(java.lang.String args, Instrumentation inst) { if (StringUtils.isBlank(args)) { return; } - String[] argsArray = args.split("\\^"); + java.lang.String[] argsArray = args.split("\\^"); if (argsArray.length != 2) { return; } @@ -61,15 +66,24 @@ public class DynamicAgent { } // 动态 Attach 时加载 Agent 的入口方法 - public static void agentmain(String args, Instrumentation inst) { + public static void agentmain(java.lang.String args, Instrumentation inst) { // doAgentTransformer - doAgentTransformer(inst, String.valueOf(System.getProperties().get(DamcCoreConstant.DAMC_ARGS_INIT_KEY))); + doAgentTransformer(inst, java.lang.String.valueOf(System.getProperties().get(DamcCoreConstant.DAMC_ARGS_INIT_KEY))); } - private static Instrumentation getInstrumentation() { + public static Instrumentation getInstrumentation() { return instrumentation; } + public static void setInstrumentation(Instrumentation instrumentation) { + DynamicAgent.instrumentation = instrumentation; + DynamicAgent.instrumentation.addTransformer(new DynamicTransformer(), true); + } + + public static void setResult(ArgsValidateResult result) { + DamcCenterConfigRepository.setArgsValidateResult(result); + } + /** * 是否完成了加载 * @@ -85,18 +99,99 @@ public class DynamicAgent { * @param inst inst * @param argsArray argsArray */ - private static void doAgentTransformer(Instrumentation inst, String args) { - // ArgsValidateResult - ArgsValidateResult result = getArgsValidate(args); - if (result == null) { - return; + private static void doAgentTransformer(Instrumentation inst, java.lang.String args) { + try { + // ArgsValidateResult + ArgsValidateResult result = getArgsValidate(args); + if (result == null) { + return; + } + DamcCenterConfigRepository.setArgsValidateResult(result); + // instrumentation + instrumentation = inst; + // 注册一个可重用的 Transformer + inst.addTransformer(new DynamicTransformer(), true); + + // ======================================== 运行时处理 ======================================== + // 获取项目中的目标ClassLoader 和 这个进行匹配 + Object appRunnerClassLoaderName = System.getProperties().get(DamcCoreConstant.APP_RUNNER_CLASS_LOADER); + if (appRunnerClassLoaderName == null) { + return; + } + + java.lang.String className = java.lang.String.valueOf(appRunnerClassLoaderName); + if (StringUtils.isEmpty(className)) { + return; + } + Set classLoaders = listClassLoaders(); + for (ClassLoader clazzLoader : classLoaders) { + if (clazzLoader == null) { + continue; + } + if (!StringUtils.equals(clazzLoader.getClass().getName(), className)) { + continue; + } + + Class damcCoreStartClazz = clazzLoader.loadClass("cn.icanci.loopstack.damc.core.DamcCoreStart"); + Object start = damcCoreStartClazz.newInstance(); + Class argsValidateResultClazz = clazzLoader.loadClass("cn.icanci.loopstack.damc.cache.ArgsValidateResult"); + Object startResult = argsValidateResultClazz.newInstance(); + + Field[] fields = startResult.getClass().getDeclaredFields(); + for (Field field : fields) { + if (StringUtils.equals(field.getName(), "damcCenterAddress")) { + field.setAccessible(true); + field.set(startResult, result.getDamcCenterAddress()); + } + if (StringUtils.equals(field.getName(), "damcCenterPort")) { + field.setAccessible(true); + field.set(startResult, result.getDamcCenterPort()); + } + if (StringUtils.equals(field.getName(), "mockedProjectPort")) { + field.setAccessible(true); + field.set(startResult, result.getMockedProjectPort()); + } + if (StringUtils.equals(field.getName(), "mockedProjectEnv")) { + field.setAccessible(true); + field.set(startResult, result.getMockedProjectEnv()); + } + if (StringUtils.equals(field.getName(), "mockedProjectName")) { + field.setAccessible(true); + field.set(startResult, result.getMockedProjectName()); + } + if (StringUtils.equals(field.getName(), "mockedProjectCode")) { + field.setAccessible(true); + field.set(startResult, result.getMockedProjectCode()); + } + + } + + Method[] methods = start.getClass().getMethods(); + for (Method method : methods) { + if (StringUtils.equals(method.getName(), "setInitParam")) { + method.invoke(start, startResult, inst); + } + } + } + } catch (Exception e) { + // TODO logs + System.out.println(e); } - DamcCenterConfigRepository.setArgsValidateResult(result); + } - // instrumentation - instrumentation = inst; - // 注册一个可重用的 Transformer - inst.addTransformer(new DynamicTransformer(), true); + public static Set listClassLoaders() { + if (instrumentation == null) { + System.out.println("Instrumentation is not initialized!"); + return Sets.newHashSet(); + } + + // 获取所有已加载的类 + Set classLoaders = Sets.newHashSet(); + for (Class clazz : instrumentation.getAllLoadedClasses()) { + ClassLoader classLoader = clazz.getClassLoader(); + classLoaders.add(classLoader); + } + return classLoaders; } /** @@ -106,7 +201,7 @@ public class DynamicAgent { * @param args args * @return ArgsValidateResult */ - private static ArgsValidateResult getArgsValidate(String args) { + private static ArgsValidateResult getArgsValidate(java.lang.String args) { // 启动参数为空,不处理 if (StringUtils.isEmpty(args)) { return null; @@ -118,7 +213,7 @@ public class DynamicAgent { } // 127.0.0.1;127.0.0.2 - String damcCenterAddress = arg[0]; + java.lang.String damcCenterAddress = arg[0]; // 9191 if (!NumberUtils.isNumber(arg[1])) { return null; @@ -141,12 +236,12 @@ public class DynamicAgent { return null; } - String mockedProjectCode = arg[5]; + java.lang.String mockedProjectCode = arg[5]; if (StringUtils.isBlank(mockedProjectCode)) { return null; } - return new ArgsValidateResult(damcCenterAddress, damcCenterPort, mockedProjectPort, mockedProjectEnv, mockedProjectName, mockedProjectCode); + return new ArgsValidateResult(damcCenterAddress, damcCenterPort, mockedProjectPort, mockedProjectEnv.getEnvCode(), mockedProjectName, mockedProjectCode); } /** @@ -169,7 +264,7 @@ public class DynamicAgent { */ static class DynamicTransformer implements ClassFileTransformer { @Override - public byte[] transform(ClassLoader loader, String clazzName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { + public byte[] transform(ClassLoader loader, java.lang.String clazzName, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { return DynamicAgentClassCache.doTransform(classBeingRedefined, classfileBuffer); } } diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgentClassCache.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgentClassCache.java index 388ba43d2cc0eda80d6039e03b71209ac3c92119..e757a5527e8a517837aa6d9379c18107758c0505 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgentClassCache.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/DynamicAgentClassCache.java @@ -16,19 +16,18 @@ */ package cn.icanci.loopstack.damc.core.dynamic; -import static org.objectweb.asm.ClassReader.EXPAND_FRAMES; +import static damc.objectweb.asm.ClassReader.EXPAND_FRAMES; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.*; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; - -import cn.icanci.loopstack.damc.spi.model.refresh.DynamicConditionWrapper; import cn.icanci.loopstack.damc.core.dynamic.visitor.ModifierClassVisitor; +import cn.icanci.loopstack.damc.spi.model.refresh.DynamicConditionWrapper; +import damc.objectweb.asm.ClassReader; +import damc.objectweb.asm.ClassVisitor; +import damc.objectweb.asm.ClassWriter; /** * @author icanci @@ -72,8 +71,8 @@ public class DynamicAgentClassCache { return defaultTransform(classfileBuffer); } Set wrappers = CLASS_CONDITIONS.get(classBeingRedefined); - ClassReader cr = new ClassReader(classBeingRedefined.getTypeName()); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); + ClassReader cr = getClassReader(classBeingRedefined); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); for (DynamicConditionWrapper wrapper : wrappers) { if (wrapper.getClassType() == ModifierClassVisitor.class) { @@ -92,6 +91,15 @@ public class DynamicAgentClassCache { } } + private static ClassReader getClassReader(Class classBeingRedefined) throws IOException { + try { + return new ClassReader(classBeingRedefined.getTypeName()); + } catch (Throwable e) { + String clazzName = classBeingRedefined.getTypeName().replace('.', '/') + ".class"; + return new ClassReader(classBeingRedefined.getClassLoader().getResourceAsStream(clazzName)); + } + } + /** * printNewByteArray * diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/ModifierClassVisitor.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/ModifierClassVisitor.java index 7edfd6739eb2035659b444c579a39c721a16fc66..8d52f70dee791d8878923b3cf847446befd1521b 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/ModifierClassVisitor.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/ModifierClassVisitor.java @@ -16,14 +16,13 @@ */ package cn.icanci.loopstack.damc.core.dynamic.visitor; -import static org.objectweb.asm.Opcodes.ASM9; +import static damc.objectweb.asm.Opcodes.ASM9; import java.util.List; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; - import cn.icanci.loopstack.damc.spi.model.refresh.DynamicCondition; +import damc.objectweb.asm.ClassVisitor; +import damc.objectweb.asm.MethodVisitor; public class ModifierClassVisitor extends ClassVisitor { private final List conditions; diff --git a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/VisitorModifier.java b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/VisitorModifier.java index b6e619eae51e15be32fac5132e99106cce30507a..a624fce4459b973373a6494462c5a07461273be8 100644 --- a/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/VisitorModifier.java +++ b/damc-core/src/main/java/cn/icanci/loopstack/damc/core/dynamic/visitor/VisitorModifier.java @@ -16,18 +16,17 @@ */ package cn.icanci.loopstack.damc.core.dynamic.visitor; -import static org.objectweb.asm.Opcodes.ASM9; +import static damc.objectweb.asm.Opcodes.ASM9; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - import cn.icanci.loopstack.damc.spi.model.refresh.DynamicCondition; +import damc.objectweb.asm.Label; +import damc.objectweb.asm.MethodVisitor; +import damc.objectweb.asm.Opcodes; +import damc.objectweb.asm.Type; /** * http://localhost:9090/refresh/refresh diff --git a/spring-web-application-test/pom.xml b/spring-web-application-test/pom.xml index e46bac10ffc698214d41004cb424e2de15dd7aff..be2834ae375e46081e171db432a27be9354e2fd5 100644 --- a/spring-web-application-test/pom.xml +++ b/spring-web-application-test/pom.xml @@ -47,16 +47,16 @@ aspectjweaver ${aspectjweaver.version} - - org.ow2.asm - asm - ${asm.version} - - - org.ow2.asm - asm-commons - ${asm.version} - + + + + + + + + + + cn.hutool hutool-all @@ -86,14 +86,14 @@ org.aspectj aspectjweaver - - org.ow2.asm - asm - - - org.ow2.asm - asm-commons - + + + + + + + + cn.hutool hutool-all