[英]Add a static method to class and delegate to an existing method
這就是我所擁有的。 代理商:
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)
...
因此,看起來方法匹配器不匹配。 有這些參數類型有一個靜態方法,但是當它被過濾,它不是在列表中。 我一定缺少靜態方法的東西嗎?
我確實設法使其與Javassist一起使用,但是我想了解為什么字節伙伴無法正常工作。
Matcher API僅用於動態檢測虛擬調用,在這種情況下,這種類型相關的檢測有意義(主要是由於泛型)。 但是,對於靜態方法,您確實知道聲明方法的確切類型以及該方法的類型,因此應改為提供對靜態方法的引用:
MethodCall.invoke(typeDescription
.getDeclaredMethods()
.filter(named("run")
.and(isStatic()
.and(takesArguments(Object.class, String[].class)))
.getOnly()).withAllArguments())
您正在使用的方法的javadoc中也提到了這一點:
調用與指定匹配器匹配的檢測類型的唯一虛擬方法。
但是,我應該提供更多有關為何以這種方式構建API的背景知識。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.