diff --git a/agent2-loader/src/main/java/com/github/akwei/agentdemo/agent2/loader/AgentClassLoader.java b/agent2-loader/src/main/java/com/github/akwei/agentdemo/agent2/loader/AgentClassLoader.java index a261ea0..166d622 100644 --- a/agent2-loader/src/main/java/com/github/akwei/agentdemo/agent2/loader/AgentClassLoader.java +++ b/agent2-loader/src/main/java/com/github/akwei/agentdemo/agent2/loader/AgentClassLoader.java @@ -21,6 +21,9 @@ public void addClassLoader(ClassLoader classLoader) { @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { try { + if (name.startsWith("com.github.akwei")) { + System.out.println("AgentClassLoader: " + name); + } return super.loadClass(name, resolve); } catch (ClassNotFoundException e) { for (ClassLoader external : otherClassLoaders) { diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/MyAgent2.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/MyAgent2.java index cd7acdd..d8c1d09 100644 --- a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/MyAgent2.java +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/MyAgent2.java @@ -1,9 +1,12 @@ package com.github.akwei.agentdemo.agent2; +import com.github.akwei.agentdemo.agent2.test.*; import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.loading.ClassInjector; import net.bytebuddy.implementation.FieldAccessor; +import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.jar.asm.Opcodes; import net.bytebuddy.pool.TypePool; @@ -27,42 +30,62 @@ public class MyAgent2 { } } -// public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { -//// premain1(agentArgs, instrumentation); -// premain2(agentArgs, instrumentation); -//// premain3(agentArgs, instrumentation); -// -// } + public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { +// premain10(agentArgs, instrumentation); + premain20(agentArgs, instrumentation); +// premain30(agentArgs, instrumentation); +// premain40(agentArgs, instrumentation); -// public static void premain(String agentArgs, Instrumentation instrumentation) { -// ClassLoader agentClassLoader = MyAgent2.class.getClassLoader(); -// new AgentBuilder.Default() -// .with(new AgentListener()) -// .type(nameEndsWith("Bean")) -// .transform(new AgentBuilder.Transformer.ForAdvice() -// .include(agentClassLoader) -// .advice(nameStartsWith("printInfo"), -// "com.github.akwei.agentdemo.agent2.Agent2Advice")) -// .installOn(instrumentation); -// } + } -// public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception { + public static void premain10(String agentArgs, Instrumentation instrumentation) { + ClassLoader agentClassLoader = MyAgent2.class.getClassLoader(); + new AgentBuilder.Default() + .with(new AgentListener()) + .type(nameEndsWith("Bean")) + .transform(new AgentBuilder.Transformer.ForAdvice() + .include(agentClassLoader) + .advice(nameStartsWith("printInfo"), + "com.github.akwei.agentdemo.agent2.Agent2Advice")) + .installOn(instrumentation); + } + + public static void premain20(String agentArgs, Instrumentation instrumentation) throws Exception { // injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.Agent2Advice2Delegate"); -// ClassLoader agentClassLoader = MyAgent2.class.getClassLoader(); -// new AgentBuilder.Default() -// .with(new AgentListener()) -// .type(nameEndsWith("Bean")) -// .transform((builder, typeDescription, classLoader, module) -> { -// addUserClassLoader(agentClassLoader, classLoader); -// return new AgentBuilder.Transformer.ForAdvice() -// .include(agentClassLoader) -// .advice(nameStartsWith("printInfo"), "com.github.akwei.agentdemo.agent2.Agent2Advice2") -// .transform(builder, typeDescription, classLoader, module); -// }) -// .installOn(instrumentation); -// } + injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.test.TestDispatcher"); + injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.test.TestAction"); + injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.test.TestFieldAccessor"); + injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.test.TestMethodDelegate"); + ClassLoader agentClassLoader = MyAgent2.class.getClassLoader(); + new AgentBuilder.Default() + .with(new AgentListener()) + .type(nameEndsWith("Bean")) + //动态添加字段 + .transform((builder, typeDescription, classLoader, javaModule) -> + builder.defineField("value", Object.class, Opcodes.ACC_PUBLIC) + .implement(TestFieldAccessor.class) + .intercept(FieldAccessor.ofField("value"))) + //动态添加方法 + .transform(((builder, typeDescription, classLoader, javaModule) -> + builder.defineMethod("newMethod", String.class, Visibility.PRIVATE) + .withParameters(String.class, Long.class, Boolean.class) + .intercept(MethodDelegation.to(TestMethodDelegate.class))) + ) + .transform((builder, typeDescription, classLoader, module) -> { + System.out.println("transform classloader " + classLoader); + addUserClassLoader(agentClassLoader, classLoader); + TestAction testAction = newInstance("com.github.akwei.agentdemo.agent2.test.TestActionImpl", agentClassLoader); + System.out.println("transform test action classloader " + testAction.getClass().getClassLoader()); + TestDispatcher.setAction("test", testAction); + return new AgentBuilder.Transformer.ForAdvice() + .include(agentClassLoader) + .advice(nameStartsWith("printInfo"), "com.github.akwei.agentdemo.agent2.test.TestAdvice") + .transform(builder, typeDescription, classLoader, module); + }) + .installOn(instrumentation); + } - public static void premain(String agentArgs, Instrumentation instrumentation) + public static void premain30(String agentArgs, Instrumentation instrumentation) throws Exception { injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.Dispatcher"); @@ -112,8 +135,7 @@ public static void premain(String agentArgs, Instrumentation instrumentation) .installOn(instrumentation); } - public static void premain4(String agentArgs, Instrumentation instrumentation) - throws Exception { + public static void premain40(String agentArgs, Instrumentation instrumentation) throws Exception { injectToBootstrapClassLoader(instrumentation, "com.github.akwei.agentdemo.agent2.Dispatcher"); injectToBootstrapClassLoader(instrumentation, diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAction.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAction.java new file mode 100644 index 0000000..8535ba1 --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAction.java @@ -0,0 +1,17 @@ +package com.github.akwei.agentdemo.agent2.test; + +import java.util.Map; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 14:23 + */ +public interface TestAction { + + + Map enter(Object obj); + + void exit(Map map, Object obj); + +} diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestActionImpl.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestActionImpl.java new file mode 100644 index 0000000..41dbe4e --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestActionImpl.java @@ -0,0 +1,50 @@ +package com.github.akwei.agentdemo.agent2.test; + +import org.apache.commons.lang3.ObjectUtils; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 14:29 + */ +public class TestActionImpl implements TestAction { + + @Override + public Map enter(Object obj) { + //agent custom class loader + System.out.println("test action enter class loader: " + this.getClass().getClassLoader()); + System.out.println("test action enter obj utils is empty " + ObjectUtils.isEmpty(obj)); + Map map = new HashMap<>(); + map.put("beginTime", System.currentTimeMillis() - 2000); + ((TestFieldAccessor) obj).setValue(map); + Object result; + try { + Method newMethod = obj.getClass().getDeclaredMethod("newMethod", String.class, Long.class, Boolean.class); + newMethod.setAccessible(true); + result = newMethod.invoke(obj, "s1", 10L, true); + map.put("result", result); + } catch (Exception e) { + throw new RuntimeException(e); + } + return map; + } + + @Override + public void exit(Map map, Object obj) { + System.out.println("test action exit class loader: " + this.getClass().getClassLoader()); + System.out.println("test action exit obj utils is empty " + ObjectUtils.isEmpty(obj)); + Map value = (Map) ((TestFieldAccessor) obj).getValue(); + long beginTimeByFieldAccessor = (long) value.get("beginTime"); + long beginTime = (long) map.get("beginTime"); + System.out.println("beginTime(field accessor)=" + beginTimeByFieldAccessor + + ",beginTime(return map get value)=" + beginTime + + ", equals " + (beginTimeByFieldAccessor == beginTime)); + System.out.println(map.get("result")); + long duration = System.currentTimeMillis() - beginTime; + System.out.println("test advice exit duration " + duration + "ms"); + } +} diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAdvice.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAdvice.java new file mode 100644 index 0000000..047a0e5 --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestAdvice.java @@ -0,0 +1,31 @@ +package com.github.akwei.agentdemo.agent2.test; + +import net.bytebuddy.asm.Advice; + +import java.util.Map; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 14:30 + */ +public class TestAdvice { + + + @Advice.OnMethodEnter + public static Map enter(@Advice.This Object obj) { + //app class loader + System.out.println("test advice enter class loader: " + obj.getClass().getClassLoader()); + TestAction action = TestDispatcher.getAction("test"); + Map map = action.enter(obj); + return map; + } + + @Advice.OnMethodExit + public static void exit(@Advice.Enter Map map, + @Advice.This Object obj) { + System.out.println("test advice exit class loader: " + obj.getClass().getClassLoader()); + TestAction action = TestDispatcher.getAction("test"); + action.exit(map, obj); + } +} diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestDispatcher.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestDispatcher.java new file mode 100644 index 0000000..4f3eefb --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestDispatcher.java @@ -0,0 +1,24 @@ +package com.github.akwei.agentdemo.agent2.test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 14:23 + */ +public class TestDispatcher { + + private static final Map MAP = new HashMap<>(); + + public static void setAction(String key, TestAction action) { + MAP.put(key, action); + } + + public static TestAction getAction(String key) { + return MAP.get(key); + } + + +} diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestFieldAccessor.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestFieldAccessor.java new file mode 100644 index 0000000..d68be58 --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestFieldAccessor.java @@ -0,0 +1,13 @@ +package com.github.akwei.agentdemo.agent2.test; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 20:53 + */ +public interface TestFieldAccessor { + + void setValue(Object value); + + Object getValue(); +} diff --git a/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestMethodDelegate.java b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestMethodDelegate.java new file mode 100644 index 0000000..92c4ace --- /dev/null +++ b/agent2/src/main/java/com/github/akwei/agentdemo/agent2/test/TestMethodDelegate.java @@ -0,0 +1,14 @@ +package com.github.akwei.agentdemo.agent2.test; + +/** + * @author zhujiajun + * @version 1.0 + * @since 2022/12/4 21:26 + */ +public class TestMethodDelegate { + + public static String newMethod(String s1, Long l1, Boolean b1) { + System.out.println("TestMethodDelegate newMethod"); + return "TestMethodDelegate newMethod_" + s1 + "_" + l1 + "_" + b1; + } +} diff --git a/app/src/main/java/com/github/akwei/agentdemo/app/Main.java b/app/src/main/java/com/github/akwei/agentdemo/app/Main.java index c500da9..9af6bd8 100644 --- a/app/src/main/java/com/github/akwei/agentdemo/app/Main.java +++ b/app/src/main/java/com/github/akwei/agentdemo/app/Main.java @@ -3,6 +3,10 @@ public class Main { public static void main(String[] args) { - System.out.println("hello"); +// System.out.println("hello"); + UserBean userBean = new UserBean(); + userBean.setUserId(10); + userBean.setName("aaa"); + userBean.printInfo("a"); } }