cglib - 方法拦截器和方法拦截器最终确定?

发布于 2024-11-17 19:04:23 字数 990 浏览 3 评论 0原文

我使用 cglib MethodInterceptor 来包装服务。在每次调用服务时,它都应该打开数据会话,将调用传递给服务,最后关闭会话。

但是,我注意到从 Finalizer 调用时它会出现错误。我得到以下堆栈跟踪:

java.lang.IllegalArgumentException: interface my.pkg.SomeInterface is not visible from class loader
        at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
        at my.pkg.ProxyFactory.create(ProxyFactory.java:68)
        at my.pkg.SomeService.make(SomeService.java:181)
        at my.pkg.SomeService$SessionWrappingInterceptor.intercept(SomeService.java:1275)
        at my.pkg.SomeService$$EnhancerByCGLIB$$b58faf6a.finalize(<generated>)
        at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
        at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
        at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)

我做错了什么?我该如何解决?

I use cglib MethodInterceptor to wrap a service. In each call to the service it's supposed to open data session, pass call to the service and finally close the session.

However, I noticed it misbehaves when invoked from Finalizer. I get the following stacktrace:

java.lang.IllegalArgumentException: interface my.pkg.SomeInterface is not visible from class loader
        at java.lang.reflect.Proxy.getProxyClass(Proxy.java:353)
        at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:581)
        at my.pkg.ProxyFactory.create(ProxyFactory.java:68)
        at my.pkg.SomeService.make(SomeService.java:181)
        at my.pkg.SomeService$SessionWrappingInterceptor.intercept(SomeService.java:1275)
        at my.pkg.SomeService$EnhancerByCGLIB$b58faf6a.finalize(<generated>)
        at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
        at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
        at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)

What am I doing wrong? How can I resolve it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

十秒萌定你 2024-11-24 19:04:23

当终结器最终选择要终结的对象(或 CGLIB 代理对象)时,垃圾收集器已确定您的对象无法访问并且即将被丢弃/收集。我们假设这不是唯一被收集的对象,事实上它过去可能使用过的其他对象(包括它们的类加载器)也被收集了。

您的问题中没有足够的信息来确定发生了什么,但我的一般猜测是您的 ProxyFactory 正在做的工作需要曾经可以被该类加载器访问但不再可以访问的类,可能是由于以下事实您正处于垃圾收集的最后阶段。

我经历了惨痛的教训才知道,处理 Finalize() 调用的代理是非常危险的。在大多数情况下,您的代理目标实际上不需要处理该调用,但如果需要处理该调用,请不要在代理处理程序中执行任何将创建、初始化或以其他方式创建对代理目标的引用的操作。 (例如,我的情况是一个按需加载的对象。当调用finalize()时,如果该对象之前没有被加载过,它会加载它并将值缓存在创建新的强引用链的地方,从而不允许代理类、它的类加载器以及它引用的许多其他类都会被收集。)

我的建议(尽管已经很晚了)是禁止您的代理处理 Finalize()。 CGLIB 的增强器可以被给予 CallbackFilters 来指示不对 Finalize() 方法执行任何操作,或者如果您使用简单的 MethodInterceptor,您可以自己检查。

最后一条评论:小心使用 CallbackFilter。它们还可能导致内存泄漏,特别是如果它们来自与 CGLIB 不同的类加载器!您最终将得到 CGLIB 生成的对象,这些对象保留着不会被垃圾收集的 CallbackFilter 实例。

When the finalizer finally picks your object (or your CGLIB proxy object) to finalize, the garbage collector has determined that your object is unreachable and is about to be discarded/collected. Let's assume that this is not the only object being collected, and in fact other objects that it might have used in the past (including their classloaders) have since also been collected.

There's not enough information in your question to be certain about what is going on, but the general guess I have is that the work your ProxyFactory is doing requires classes that USED to be accessible to this classloader but no longer are, possibly due to the fact that you are in the last stages of garbage collection.

I've learned the hard way that proxies that handle finalize() calls are downright dangerous. In most cases your proxy target really doesn't need to handle that call, but if it does, don't do anything in your proxy handler that is going to create, initialize or otherwise create references to the proxy target. (For instance, my case was a load-on-demand object. When finalize() was called, if the object had not been previously loaded, it would load it and cache the value somewhere that created a new strong reference chain, thereby disallowing the proxy class, its classloader, and many other classes it referenced to be collected. Massive memory leak.)

My advice (late tho it is) is to disallow your proxy from handling finalize(). CGLIB's Enhancer can be given CallbackFilters to indicate not to do anything with the finalize() method, or if you're using the simple MethodInterceptor, you can check for that yourself.

One last comment: careful with the CallbackFilters. They can also cause you memory leaks especially if they are coming from a different classloader than CGLIB is coming from! You're going to end up with CGLIB-generated objects that hold on to your CallbackFilter instances that will not be garbage collected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文