检测 Spring Boot 应用程序时的类路径问题
Classpath problems while Instrumenting Springboot application
我有一个 springboot 应用程序,我正在尝试使用 bytebuddy 对其进行检测。我正在 运行 解决 class 我无法理解的路径问题。
首先,以下是这方面的其他文献:
https://github.com/raphw/byte-buddy/issues/473
https://github.com/raphw/byte-buddy/issues/87
https://github.com/raphw/byte-buddy/issues/109
https://github.com/raphw/byte-buddy/issues/473
https://github.com/raphw/byte-buddy/issues/489
https://github.com/spring-projects/spring-boot/issues/4868
https://github.com/alibaba/transmittable-thread-local/issues/161
问题是 Spring-boot 将应用程序捆绑到一个 uber-jar 中,其中包含其他 jar
这里要注意的一件事是,如果我 运行 使用 IntelliJ 的应用程序,它不会通过 main class 使用 uber-jar 和 运行s一堆罐子作为 class 路径参数。
由于这种差异,当 运行通过 uber-jar(java -jar target/demo-0.0.1-SNAPSHOT.jar
) 连接时,某些 classes 在代理 运行s 时不可用. classes 在应用程序主程序时是可加载的,因为 spring-boot 使用它自己的 classloader,它是在 b/w 代理和应用程序主方法的某个时间创建的.
我将在下面描述不同时间点的行为:
在 Agent 的 PreMain 时
Thread.currentThread().getContextClassLoader() = Launcher$AppClassLoader
Agent.class.classLoader = Launcher$AppClassLoader
Class.forName("org.springframework.web.servlet.HandlerAdapter") => ClassNotFoundException
Class.forName("javax.servlet.http.HttpServletRequest") => ClassNotFoundException
spring 和 javax classes 均未加载,因为它们不直接位于 class 路径中,按照 App Classloader。它是内罐的一部分,类似于 app.jar!/BOOT-INF/lib/some.jar
应用程序 Classloader 将无法加载它。
主要申请时Class
Thread.currentThread().getContextClassLoader() =
org.springframework.boot.loader.LaunchedURLClassLoader
DemoApplication.class.classloader = same as above
Class.forName("org.springframework.web.servlet.HandlerAdapter") => loads successfully
- javax 相同class,加载成功。
加载后,Class.forName("javax.servlet.http.HttpServletRequest").classLoader
也是一样LaunchedURLClassLoader
。
在builder.visit
调用时(当bytebuddy正在修改class定义时)
代码:
我有两个classes,SpringBootInterceptor
(包含拦截方法)和SpringBootInterceptorOne
(包含进入和退出方法)
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
.type(isSubTypeOf(HandlerAdapter.class))
.transform((builder, typeDescription, classLoader, module) ->
builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
);
}
函数intercept()
在premain路径中被调用。
函数 visit
在实际尝试加载类型时调用。那时 bytebuddy 试图拦截这些方法并修改字节码。
在此代码的当前版本中,函数 intercept()
抛出 ClassNotFoundException
并且不会发生拦截。
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerAdapter
因此,我尝试将代码更改为以下内容:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform((builder, typeDescription, classLoader, module) ->
builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
);
}
在这里,基本上是延迟加载 class。
来自 datadog 的辅助函数:
这样做之后,intercept
函数没有失败,但是 visit()
函数表现得很奇怪:
java.lang.IllegalStateException: Could not locate class file for my.package.name.SpringBootInterceptorOne
at net.bytebuddy.dynamic.ClassFileLocator$Resolution$Illegal.resolve(ClassFileLocator.java:118)
at net.bytebuddy.asm.Advice.to(Advice.java:431)
at net.bytebuddy.asm.Advice.to(Advice.java:400)
at net.bytebuddy.asm.Advice.to(Advice.java:375)
at net.bytebuddy.asm.Advice.to(Advice.java:361)
at my.package.name.SpringBootInterceptor.lambda$intercept[=13=](SpringBootInterceptor.java:30)
at net.bytebuddy.agent.builder.AgentBuilder$Transformer$Compound.transform(AgentBuilder.java:2612)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:10117)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10494)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10457)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10223)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10833)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10780)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10380)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:757)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access0(URLClassLoader.java:74)
at java.net.URLClassLoader.run(URLClassLoader.java:369)
at java.net.URLClassLoader.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethods(Class.java:1975)
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:743)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:742)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:649)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1604)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:520)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:491)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:230)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:223)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:213)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:167)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:142)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:184)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.example.demo.DemoApplication.main(DemoApplication.java:10)
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:51)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
至此,
Thread.currentThread().getContextClassLoader() => LaunchedURLClassLoader
SpringBootInterceptor.class.getClassLoader() = null
- 在调试器中输入
SpringBootInterceptor.class
window 不会失败,但是
Class.forName("my.package.name.SpringBootInterceptorOne")
=> 没有ClassDefFound
接下来,我尝试了以下操作:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform((builder, typeDescription, classLoader, module) -> {
try {
Class<?> claz = Thread.currentThread().getContextClassLoader().loadClass("my.package.name.SpringBootInterceptorOne");
return builder.visit(Advice.to(claz, claz,
new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(cl),
ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader())
)).on(named("handle").and(isMethod())));
} catch (ClassNotFoundException e) {
e.printStackTrace();
return builder;
}
}
);
}
这导致拦截器为"installed"。进入和退出方法称为okay。但是将参数转换为正确的类型会给参数类型带来错误
exit spring boot
[Ljava.lang.Object;@c83066a
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at my.package.name.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:36)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
这里有SpringBootInterceptorOne供参考:
@Advice.OnMethodExit
static void exit(@Advice.Origin final Executable executable,
@Advice.This Object handlerAdapter,
@Advice.AllArguments Object[] arguments,
@Advice.Enter final TimerContext ctx) {
// final long duration = ctx.getDuration();
System.out.println("exit spring boot");
String e = getEndpoint(arguments);
System.out.println(e);
}
public static String getEndpoint(Object[] arguments) {
System.out.println(arguments);
HttpServletRequest request = (HttpServletRequest) arguments[0];
HandlerMethod handler = (HandlerMethod) arguments[2];
return "ad";
}
更新:
根据答案中提供的建议,我尝试了以下方法:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform(new AgentBuilder.Transformer.ForAdvice()
.include(SpringBootInterceptorOne.class.getClassLoader())
.include(getClass().getClassLoader())
.advice(named("handle"), SpringBootInterceptorOne.class.getName())
);
}
它再次抛出错误:
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at io.signoz.interceptors.http.server.springboot.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:37) ~[na:na]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_242]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_242]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_242]
问题是建议 class 将作为代理的一部分加载到系统 class 加载器上,而实际应用程序代码加载到子 class系统 class 加载程序不可见的加载程序。如果您在引导加载程序上加载代理,这种情况也不会改变。因此,代理无法加载作为 uber-jar 一部分的 HttpServletRequest
class。
这是代理的典型问题,Byte Buddy 有一个标准的方法来规避它,即使用 Transformer.ForAdvice
实例而不是直接使用 Advice
class。 Byte Buddy 然后创建一个虚拟 class 加载器层次结构,该层次结构考虑由两个 class 加载器表示的 classes。
Update:问题是您正在调用系统 class 加载程序中定义的拦截器,其中 class 有问题无法使用。带注释的代码将被内联,但调用的方法不会。如果您将代码复制粘贴到带注释的方法中,行为就会如您所料。 Byte Buddy 使用带注释的代码作为模板,并重用 javac 发出的大量信息以保证快速转换。因此,库不能简单地复制方法,而应该将整个方法体提供给 javac。
我有一个 springboot 应用程序,我正在尝试使用 bytebuddy 对其进行检测。我正在 运行 解决 class 我无法理解的路径问题。
首先,以下是这方面的其他文献:
https://github.com/raphw/byte-buddy/issues/473
https://github.com/raphw/byte-buddy/issues/87
https://github.com/raphw/byte-buddy/issues/109
https://github.com/raphw/byte-buddy/issues/473
https://github.com/raphw/byte-buddy/issues/489
https://github.com/spring-projects/spring-boot/issues/4868
https://github.com/alibaba/transmittable-thread-local/issues/161
问题是 Spring-boot 将应用程序捆绑到一个 uber-jar 中,其中包含其他 jar
这里要注意的一件事是,如果我 运行 使用 IntelliJ 的应用程序,它不会通过 main class 使用 uber-jar 和 运行s一堆罐子作为 class 路径参数。
由于这种差异,当 运行通过 uber-jar(java -jar target/demo-0.0.1-SNAPSHOT.jar
) 连接时,某些 classes 在代理 运行s 时不可用. classes 在应用程序主程序时是可加载的,因为 spring-boot 使用它自己的 classloader,它是在 b/w 代理和应用程序主方法的某个时间创建的.
我将在下面描述不同时间点的行为:
在 Agent 的 PreMain 时
Thread.currentThread().getContextClassLoader() = Launcher$AppClassLoader
Agent.class.classLoader = Launcher$AppClassLoader
Class.forName("org.springframework.web.servlet.HandlerAdapter") => ClassNotFoundException
Class.forName("javax.servlet.http.HttpServletRequest") => ClassNotFoundException
spring 和 javax classes 均未加载,因为它们不直接位于 class 路径中,按照 App Classloader。它是内罐的一部分,类似于 app.jar!/BOOT-INF/lib/some.jar
应用程序 Classloader 将无法加载它。
主要申请时Class
Thread.currentThread().getContextClassLoader() =
org.springframework.boot.loader.LaunchedURLClassLoader
DemoApplication.class.classloader = same as above
Class.forName("org.springframework.web.servlet.HandlerAdapter") => loads successfully
- javax 相同class,加载成功。
加载后,Class.forName("javax.servlet.http.HttpServletRequest").classLoader
也是一样LaunchedURLClassLoader
。
在builder.visit
调用时(当bytebuddy正在修改class定义时)
代码:
我有两个classes,SpringBootInterceptor
(包含拦截方法)和SpringBootInterceptorOne
(包含进入和退出方法)
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
.type(isSubTypeOf(HandlerAdapter.class))
.transform((builder, typeDescription, classLoader, module) ->
builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
);
}
函数intercept()
在premain路径中被调用。
函数 visit
在实际尝试加载类型时调用。那时 bytebuddy 试图拦截这些方法并修改字节码。
在此代码的当前版本中,函数 intercept()
抛出 ClassNotFoundException
并且不会发生拦截。
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerAdapter
因此,我尝试将代码更改为以下内容:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform((builder, typeDescription, classLoader, module) ->
builder.visit(Advice.to(SpringBootInterceptorOne.class, SpringBootInterceptorOne.class).on(named("handle").and(isMethod())))
);
}
在这里,基本上是延迟加载 class。 来自 datadog 的辅助函数:
这样做之后,intercept
函数没有失败,但是 visit()
函数表现得很奇怪:
java.lang.IllegalStateException: Could not locate class file for my.package.name.SpringBootInterceptorOne
at net.bytebuddy.dynamic.ClassFileLocator$Resolution$Illegal.resolve(ClassFileLocator.java:118)
at net.bytebuddy.asm.Advice.to(Advice.java:431)
at net.bytebuddy.asm.Advice.to(Advice.java:400)
at net.bytebuddy.asm.Advice.to(Advice.java:375)
at net.bytebuddy.asm.Advice.to(Advice.java:361)
at my.package.name.SpringBootInterceptor.lambda$intercept[=13=](SpringBootInterceptor.java:30)
at net.bytebuddy.agent.builder.AgentBuilder$Transformer$Compound.transform(AgentBuilder.java:2612)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:10117)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:10494)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10457)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access00(AgentBuilder.java:10223)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10833)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:10780)
at java.security.AccessController.doPrivileged(Native Method)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:10380)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:757)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access0(URLClassLoader.java:74)
at java.net.URLClassLoader.run(URLClassLoader.java:369)
at java.net.URLClassLoader.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethods(Class.java:1975)
at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:743)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:742)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:681)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:649)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1604)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:520)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:491)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:230)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:223)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:213)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:167)
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:142)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:184)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:706)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at com.example.demo.DemoApplication.main(DemoApplication.java:10)
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:51)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
至此,
Thread.currentThread().getContextClassLoader() => LaunchedURLClassLoader
SpringBootInterceptor.class.getClassLoader() = null
- 在调试器中输入
SpringBootInterceptor.class
window 不会失败,但是 Class.forName("my.package.name.SpringBootInterceptorOne")
=> 没有ClassDefFound
接下来,我尝试了以下操作:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform((builder, typeDescription, classLoader, module) -> {
try {
Class<?> claz = Thread.currentThread().getContextClassLoader().loadClass("my.package.name.SpringBootInterceptorOne");
return builder.visit(Advice.to(claz, claz,
new ClassFileLocator.Compound(ClassFileLocator.ForClassLoader.of(cl),
ClassFileLocator.ForClassLoader.of(Thread.currentThread().getContextClassLoader())
)).on(named("handle").and(isMethod())));
} catch (ClassNotFoundException e) {
e.printStackTrace();
return builder;
}
}
);
}
这导致拦截器为"installed"。进入和退出方法称为okay。但是将参数转换为正确的类型会给参数类型带来错误
exit spring boot
[Ljava.lang.Object;@c83066a
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at my.package.name.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:36)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
这里有SpringBootInterceptorOne供参考:
@Advice.OnMethodExit
static void exit(@Advice.Origin final Executable executable,
@Advice.This Object handlerAdapter,
@Advice.AllArguments Object[] arguments,
@Advice.Enter final TimerContext ctx) {
// final long duration = ctx.getDuration();
System.out.println("exit spring boot");
String e = getEndpoint(arguments);
System.out.println(e);
}
public static String getEndpoint(Object[] arguments) {
System.out.println(arguments);
HttpServletRequest request = (HttpServletRequest) arguments[0];
HandlerMethod handler = (HandlerMethod) arguments[2];
return "ad";
}
更新:
根据答案中提供的建议,我尝试了以下方法:
@Override
public AgentBuilder intercept(AgentBuilder agentBuilder) {
return agentBuilder
// .type(isSubTypeOf(HandlerAdapter.class))
.type(not(isInterface())
.and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))))
.transform(new AgentBuilder.Transformer.ForAdvice()
.include(SpringBootInterceptorOne.class.getClassLoader())
.include(getClass().getClassLoader())
.advice(named("handle"), SpringBootInterceptorOne.class.getName())
);
}
它再次抛出错误:
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at io.signoz.interceptors.http.server.springboot.SpringBootInterceptorOne.getEndpoint(SpringBootInterceptorOne.java:37) ~[na:na]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_242]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_242]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.30.jar!/:9.0.30]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_242]
问题是建议 class 将作为代理的一部分加载到系统 class 加载器上,而实际应用程序代码加载到子 class系统 class 加载程序不可见的加载程序。如果您在引导加载程序上加载代理,这种情况也不会改变。因此,代理无法加载作为 uber-jar 一部分的 HttpServletRequest
class。
这是代理的典型问题,Byte Buddy 有一个标准的方法来规避它,即使用 Transformer.ForAdvice
实例而不是直接使用 Advice
class。 Byte Buddy 然后创建一个虚拟 class 加载器层次结构,该层次结构考虑由两个 class 加载器表示的 classes。
Update:问题是您正在调用系统 class 加载程序中定义的拦截器,其中 class 有问题无法使用。带注释的代码将被内联,但调用的方法不会。如果您将代码复制粘贴到带注释的方法中,行为就会如您所料。 Byte Buddy 使用带注释的代码作为模板,并重用 javac 发出的大量信息以保证快速转换。因此,库不能简单地复制方法,而应该将整个方法体提供给 javac。