java – cglib – MethodInterceptor&finalize?

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

但是,我注意到从Finalizer调用它时行为不端.我得到以下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)

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

解决方法:

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

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

我已经学会了处理finalize()调用的代理很难的方法.在大多数情况下,您的代理目标实际上不需要处理该调用,但如果确实如此,请不要在代理处理程序中执行任何操作,以创建,初始化或以其他方式创建对代理目标的引用. (例如,我的情况是按需加载对象.当调用finalize()时,如果对象之前没有加载过,它会加载它并将值缓存到某个创建新的强引用链的地方,从而禁止代理类,它的类加载器,以及它引用的许多其他类.大量内存泄漏.)

我的建议(最晚)是禁止你的代理处理finalize(). CGLIB的Enhancer可以被赋予CallbackFilters以指示不对finalize()方法做任何事情,或者如果你使用简单的MethodInterceptor,你可以自己检查.

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

上一篇:java – Spring注释与我的设计指南相冲突


下一篇:深入理解java动态代理的两种实现方式(JDK/Cglib)