这就是我所拥有的。代理人:
public static void premain(String args, Instrumentation inst) throws Exception {
new AgentBuilder.Default()
.type(ElementMatchers.named("org.springframework.boot.SpringApplication"))
.transform(new SpringApplicationTransformer())
.installOn(inst);
}
和变压器:
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
try {
builder = builder
.defineMethod("run", classLoader.loadClass(
"org.springframework.context.ConfigurableApplicationContext"),
Modifier.PUBLIC | Modifier.STATIC)
.withParameter(Class.class).withParameter(String[].class)
.intercept(MethodCall
.invoke(named("run").and(isStatic()
.and(takesArguments(Object.class, String[].class))))
.withAllArguments());
return builder;
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
我可以在调试器中看到变换器被调用并成功完成,但我仍然无法调用该方法:
$ java -javaagent:target/spring-boot-legacy-agent-0.0.1-SNAPSHOT-agent.jar -jar target/spring-boot-legacy-agent-0.0.1-SNAPSHOT.jar --thin.profile=old
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.wrapper.ThinJarWrapper.launch(ThinJarWrapper.java:118)
at org.springframework.boot.loader.wrapper.ThinJarWrapper.main(ThinJarWrapper.java:90)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.thin.ThinJarLauncher.launch(ThinJarLauncher.java:186)
at org.springframework.boot.loader.thin.ThinJarLauncher.main(ThinJarLauncher.java:133)
... 6 more
Caused by: java.lang.NoSuchMethodError: org.springframework.boot.SpringApplication.run(Ljava/lang/Class;[Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext;
at com.example.AgentApplication.main(AgentApplication.java:10)
... 15 more
向代理构建器添加侦听器可以获得更多信息:
ava.lang.IllegalStateException: class org.springframework.boot.SpringApplication does not define exactly one virtual method for (name(equals(run)) and hasParameter(hasTypes(erasures(containing(is(class java.lang.Object;), is(class [Ljava.lang.String;))))))
at net.bytebuddy.implementation.MethodCall$MethodLocator$ForElementMatcher.resolve(MethodCall.java:668)
at net.bytebuddy.implementation.MethodCall$Appender.apply(MethodCall.java:2002)
...
所以看起来matcher方法不匹配。那里的是一个带有这些参数类型的静态方法,但是当它被过滤时它不在列表中。我必须遗漏一些静态方法吗?
我确实设法让它与javassist一起工作,但我想理解为什么byte-buddy不起作用。
答案 0 :(得分:3)
匹配器API仅用于动态检测虚拟调用,其中此类型相对检测可能有意义,主要是由于泛型。但是对于静态方法,您确实知道声明方法的确切类型以及方法的类型,因此您应该提供对静态方法的引用:
MethodCall.invoke(typeDescription
.getDeclaredMethods()
.filter(named("run")
.and(isStatic()
.and(takesArguments(Object.class, String[].class)))
.getOnly()).withAllArguments())
在您使用的方法的javadoc中也提到了这一点:
调用由指定匹配器匹配的检测类型的唯一虚拟方法。
但是,我应该更多地介绍为什么以这种方式构建API。