【问题标题】:Is it possible to instrument a program that also uses dynamic bytecode generation?是否可以检测也使用动态字节码生成的程序?
【发布时间】:2022-01-24 20:24:04
【问题描述】:

我正在编写一个 Java 检测程序,它使用 Javassist (v3.26.0-GA) 的内置检测 API 来拦截目标程序中的所有方法调用。另外,我在这个程序中实现了一个 REST API 服务,使用 Java Spark 通过添加/删除转换器来发送启动/停止检测的请求,以及在检测期间获取截获的方法。

现在,当我尝试使用从 premain 附加的 Java 代理运行 WebGoat(一个开源 Spring Boot 应用程序)时,我无法成功拦截所有方法,并且在日志中,有一个 NotFoundException 被抛出Javassist。

WebGoat 中的几个类都发生了这个错误,它们都有一个相似的共同事实,即它们与 SpringCGLIB 有关。一些错误如下所示。

javassist.NotFoundException: org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$FastClassBySpringCGLIB$$88f1f22d
    at javassist.ClassPool.get(ClassPool.java:430)
    at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
    at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
    at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
    at java.base/java.lang.ClassLoader.defineClass0(Native Method)
    at java.base/java.lang.System$2.defineClass(System.java:2307)
    at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2439)
    at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2416)
    at java.base/java.lang.invoke.MethodHandles$Lookup.defineClass(MethodHandles.java:1843)
    at java.base/jdk.internal.reflect.GeneratedMethodAccessor44.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:507)
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
    at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
    at org.springframework.cglib.reflect.FastClass$Generator.create(FastClass.java:65)
    at org.springframework.cglib.proxy.MethodProxy.helper(MethodProxy.java:135)
    at org.springframework.cglib.proxy.MethodProxy.init(MethodProxy.java:76)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:216)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:783)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:137)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698)
    at org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$EnhancerBySpringCGLIB$$6ae99c75.authenticate(<generated>)
    at org.owasp.webgoat.hijacksession.HijackSessionAssignment.login(HijackSessionAssignment.java:72)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:517)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:584)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:763)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1651)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:327)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:219)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:213)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:567)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1610)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1377)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:507)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1580)
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1292)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
    at org.eclipse.jetty.server.Server.handle(Server.java:501)
    at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)
    at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
    at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)
    at java.base/java.lang.Thread.run(Thread.java:833)

javassist.NotFoundException: org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider$$EnhancerBySpringCGLIB$$6ae99c75$$FastClassBySpringCGLIB$$8c045873
    at javassist.ClassPool.get(ClassPool.java:430)
    at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
    at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
    at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
    at java.base/java.lang.ClassLoader.defineClass0(Native Method)
    at java.base/java.lang.System$2.defineClass(System.java:2307)
... similar stacktrace as above
javassist.NotFoundException: org.owasp.webgoat.session.UserSessionData$$FastClassBySpringCGLIB$$2b6b54bc
    at javassist.ClassPool.get(ClassPool.java:430)
    at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
    at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
    at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:541)
    at java.base/java.lang.ClassLoader.defineClass0(Native Method)
    at java.base/java.lang.System$2.defineClass(System.java:2307)
... similar stacktrace as above

[IMPACTRACER-CORE] ERROR [2021-12-24 10:34:20]: NotFoundException on class 'org/owasp/webgoat/session/UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3': org.owasp.webgoat.session.UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3
javassist.NotFoundException: org.owasp.webgoat.session.UserSessionData$$EnhancerBySpringCGLIB$$bbb61fe2$$FastClassBySpringCGLIB$$34cb52d3
    at javassist.ClassPool.get(ClassPool.java:430)
    at com.sparrow.sptracer.core.transformer.AbstractMethodTransformer.transform(AbstractMethodTransformer.java:87)
    at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
    at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
... similar stacktrace as above

我的猜测是 WebGoat 在其 Spring Boot 环境中使用 cglib 来动态生成字节码,而相应的类原本不包含在 WebGoat 的类路径中,所以javassist.ClassPool.get(className) 抛出了错误。

我创建 ClassPool 对象的代码如下。

String name = Descriptor.toJavaName(className);

            try {
                ClassPool cp = ClassPool.getDefault();
                cp.childFirstLookup = true;
                cp.appendClassPath(new LoaderClassPath(loader));

                CtClass cc = cp.get(name);
                Logger.debug("Checking class %s", name);

                CtMethod[] methods = cc.getDeclaredMethods();
                Logger.debug("Altering %d methods in %s", methods.length, wut);
                for (CtMethod m : methods) {
                    // do some code insertion
                }
                bytecode = cc.toBytecode();
                cc.detach();
            } catch (NotFoundException e) {
                Logger.error("NotFoundException on class '%s': %s", className, e.getMessage());
                e.printStackTrace();
            } catch (CannotCompileException e) {
                Logger.error("Cannot compile class '%s': %s", className, e.getMessage());
                e.printStackTrace(System.out);
            } catch (IOException e) {
                Logger.error("IOException while transforming class '%s': %s", className, e.getMessage());
            } catch (Exception ex) {
                Logger.error("Generic exception occurred while transforming class '%s': %s", className, ex.getMessage());
                ex.printStackTrace(System.out);
            }

当我尝试与 localhost:8080 上的 WebGoat 应用程序交互时发生上述错误,尝试使用 Java Spark REST API 发送具有特定 ID 的“start istrumentation”请求,因此每当我发送此请求时,它都会触发 inst.addTransformer方法来创建一个新的 Transformer 并将其添加到检测对象。

此错误的原因可能是什么?我假设 WebGoat 本身正在使用一些检测,这意味着我正在检测一个检测的应用程序,我不知道这是否可能。

任何见解将不胜感激。

【问题讨论】:

  • 未找到的类是动态代理,Spring 框架大量使用这些代理来实现 AOP。 Spring 可以同时使用 JDK 动态接口代理和 CGLIB 代理,后者就是我们在这里看到的。也许您应该简单地忽略这些类型的类。它们实际上是动态创建的,因此得名。但它们是动态(子)类生成的结果,而不是字节码转换的结果。
  • @kriegaex 是的,我考虑过忽略那些动态生成的类,但我的应用程序的重点是在用户与 Web 应用程序交互时捕获每个方法调用(例如单击按钮等)。在这种情况下,是否可以忽略这些类型的动态生成的类?我想确保不会错过任何方法调用。
  • 由于这些类只是动态代理,它们要么将调用转发到原始方法,要么首先/代替调用一些 AOP 或拦截器逻辑。无论哪种方式,您都不会错过任何重要的东西,这些代理更像是交换机或路由器,实际显示发生在其他地方。我建议你简单地尝试一个带有一两个方面的小游乐场项目。
  • 如果我的建议能帮助您解决问题,请告诉我。然后我可以将 cmets 转换为您可以接受的答案,以便正式将问题标记为已回答。
  • @kriegaex 谢谢。它确实有助于澄清事情。我没有使用 Spring Boot 应用程序的经验,所以我想我将不得不进一步研究它是如何工作的。如果我只想忽略那些动态代理类,我应该如何更改Javassist代码CtClass cc = cp.get(name);,我想我可以放一个if语句,但是我将如何检查字符串className是否是动态代理类?如果你能写一个答案,那就太好了!我会接受的。

标签: java spring-boot instrumentation javassist webgoat


【解决方案1】:

来自以前的 cmets:

未找到的类是 Spring Framework 大量使用的动态代理,以实现 AOP。 Spring 可以同时使用 JDK 动态接口代理和 CGLIB 代理,后者就是我们在这里看到的。也许您应该简单地忽略这些类型的类。它们实际上是动态创建的,因此得名。但它们是动态(子)类生成的结果,而不是字节码转换的结果。

是的,我考虑过忽略那些动态生成的类,但我的应用程序的重点是在用户与 Web 应用程序交互时捕获每个方法调用(例如单击按钮等)。在这种情况下,是否可以忽略这些类型的动态生成的类?我想确保不会错过任何方法调用。

由于这些类只是动态代理,它们要么将调用转发到原始方法,要么首先/代替调用一些 AOP 或拦截器逻辑。无论哪种方式,您都不会错过任何重要的东西,这些代理更像是交换机或路由器,实际显示发生在其他地方。我建议你简单地尝试一个具有一两个方面的小游乐场项目。

您还询问了如何通过名称检测和忽略动态代理:

  • CGLIB 代理: Spring 的 CGLIB 代理包含子字符串,如 $$FastClassBySpringCGLIB$$$$EnhancerBySpringCGLIB$$,后跟代表 4 个十六进制字节的 8 个字符。您可以匹配正则表达式,保持简单并匹配子字符串BySpringCGLIB$$。如果非 Spring CGLIB 代理也在您的应用程序的某个地方使用,您将不得不注意其他命名模式。但是,如果不过滤它们,您可能会遇到与以前类似的错误,因此您会自动注意到。

  • JDK 代理:如果您的 Spring 应用程序也恰好使用 JDK 代理,您还可以过滤以 $Proxy 开头的类名,通常类似于 com.sun.proxy.$Proxy2(尾随数字不同)。根据JDK documentation“代理类的非限定名称未指定。但是,以字符串"$Proxy" 开头的类名空间是为代理类保留的。”至少对于 Oracle 和可能的 OpenJDK,您可以匹配该命名模式。如果这适用于所有 JVM,则由您来测试,是否有可能在您的环境中使用其他 JVM。我很快尝试了 Semeru OpenJ9,代理命名模式是相同的,甚至包名com.sun.proxy更新: 请注意,在更新的 JDK 版本中,JDK 代理将具有完全限定名称,例如 jdk.proxy2.$Proxy25,例如Java 16 或 17 你不应该依赖包名com.sun.proxy。添加更多案例或限制与简单类名中前导 $Proxy 的匹配。

顺便说一句,您也可以使用 AspectJ 来代替 Javassist。这听起来像是一个非常典型的用例。

【讨论】:

  • 请注意我在 JDK 16+ 中关于 JDK 代理命名的更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 2019-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-18
相关资源
最近更新 更多