Я пытаюсь создать агент, который проксирует методы, чтобы выполнить некоторую логику до и после метода. Для этого я использую Byte Buddy с делегированием метода.
Агент:
//Agent code before...
private static void instrument(String agentOps, Instrumentation inst) {
new AgentBuilder.Default().with(new Eager())
.ignore(ElementMatchers.nameContains("com.dvelopp.agenttest"))
.or(ElementMatchers.hasAnnotation(ElementMatchers.annotationType(ElementMatchers.nameContains("SpringBootApplication"))))
.type((ElementMatchers.any()))
.transform((builder, typeDescription, classLoader, module) -> builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(Interceptor.class)))
.installOn(inst);
}
//Agent code after...
Перехватчик:
public static class Interceptor {
@RuntimeType
public static Object intercept(@SuperCall Callable<?> superCall, @SuperMethod Method superMethod, @Origin Method currentMethod,
@AllArguments Object[] args, @This(optional = true) Object me) throws Exception {
//... logic
Object call = superCall.call();
//... logic
return call;
}
}
Отлично работает на простом консольном приложении. Но когда в моем classpath есть несколько общих библиотек (например, простой проект Spring Boot), он не работает должным образом. Он выдает разные ошибки, но большинство из них связаны с неожиданным отражением, подобным этому:
Exception in thread "main" java.lang.NoClassDefFoundError: sun/reflect/GeneratedMethodAccessor24
at sun.reflect.GeneratedMethodAccessor24.<clinit>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:403)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:394)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
at sun.reflect.MethodAccessorGenerator.generateMethod(MethodAccessorGenerator.java:75)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:53)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:85)
at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:60)
at org.apache.commons.logging.LogAdapter$Log4jLog.<clinit>(LogAdapter.java:135)
at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog$original$snrPR67N(LogAdapter.java:102)
at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog$original$snrPR67N$accessor$5P1QZaof(LogAdapter.java)
at org.apache.commons.logging.LogAdapter$Log4jAdapter$auxiliary$pVmPc64S.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
at org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java)
at org.apache.commons.logging.LogAdapter.createLog$original$4Ty3vM8s(LogAdapter.java:79)
at org.apache.commons.logging.LogAdapter.createLog$original$4Ty3vM8s$accessor$z3gv7aJK(LogAdapter.java)
at org.apache.commons.logging.LogAdapter$auxiliary$6cBoraQE.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
at org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java)
at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7(LogFactory.java:67)
at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7$accessor$VdtqA6Wx(LogFactory.java)
at org.apache.commons.logging.LogFactory$auxiliary$ak9XEBl0.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java)
at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7(LogFactory.java:59)
at org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7$accessor$VdtqA6Wx(LogFactory.java)
at org.apache.commons.logging.LogFactory$auxiliary$8JhBdK8k.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:126)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java)
at org.springframework.boot.SpringApplication.<clinit>(SpringApplication.java:194)
at hello.Application.main(Application.java:15)
Caused by: java.lang.ClassNotFoundException: sun.reflect.GeneratedMethodAccessor24
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 39 more
Как я вижу, эти ошибки происходят с объектами, которые являются прокси:
e.g. org.apache.commons.logging.LogFactory.getLog$original$MoDHp2B7
Я попытался отладить это глубже и обнаружил, что метод super и origin имеют разные классы. «Супер» имеет класс Proxy.
@SuperMethod Method superMethod, @Origin Method currentMethod
Есть ли способ заставить делегирование работать с такими объектами?
Добавлено:
В этом примере Spring Boot 2 (https://spring.io/guides/gs/spring-boot/) есть явная ошибка StackOverflowError:
java.lang.StackOverflowError: null
at com.dvelopp.agenttest.MethodCallContext.getCaller(MethodCallContext.java:18)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:108)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.MapPropertySource.getSource(MapPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource.getSource$accessor$d92Pg8OK(SystemEnvironmentPropertySource.java)
at org.springframework.core.env.SystemEnvironmentPropertySource$auxiliary$ATPz5tSr.call(Unknown Source)
at com.dvelopp.agenttest.Main$Interceptor.intercept(Main.java:122)