使用CGLib拦截JDK类的package-private方法

时间:2015-11-18 09:36:57

标签: java cglib

我尝试使用以下代码为java.net.SocketImpl类创建CGLib代理:

Enhancer e = new Enhancer();
e.setSuperclass(SocketImpl.class);
e.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object socketImplInstance, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
        System.out.println("Got call to " + method.getName());
        return methodProxy.invokeSuper(socketImplInstance, arguments);
    }
});
SocketImpl socketImpl = (SocketImpl)e.create();

Method m = SocketImpl.class.getDeclaredMethod("getSocket");
m.setAccessible(true);
System.out.println("getSocket: " + m.invoke(socketImpl));

m = SocketImpl.class.getDeclaredMethod("getLocalPort");
m.setAccessible(true);
System.out.println("getLocalPort: " + m.invoke(socketImpl));

作为此代码的结果,我得到一个输出:

getSocket: null
Got call to getLocalPort
getLocalPort: 0

我们没有"已经调用了getSocket",因此SocketImpl #getSocket()没有被截获。此方法与SocketImpl#getLocalPort()的区别仅在于访问级别 - SocketImpl#getLocalPort()受保护,而SocketImpl#getSocket()是包私有的。我与其他package-private方法SocketImpl#getServerSocket()。

具有相同的行为

我尝试使用用户类(根据SocketImpl是抽象的)重现此错误,但如果我们有以下内容,一切都按预期工作:

package userpackage;

public abstract class Abstract {
    void testMethod() {}
}

package somethingother;

Enhancer e = new Enhancer();
e.setSuperclass(Abstract.class);
e.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object abstractInstance, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
        System.out.println("Got call to " + method.getName());
        return methodProxy.invokeSuper(abstractInstance, arguments);
    }
});
Abstract abstrct = (Abstract)e.create();

Method m = Abstract.class.getDeclaredMethod("testMethod");
m.setAccessible(true);
System.out.println("testMethod: " + m.invoke(abstrct));

我们得到输出:

Got call to testMethod
testMethod: null

这完全没问题,这个包私有方法已被截获。

请你能帮我理解这个例子的内容,为什么我们有不同的行为。我只有一个猜测,它可能与SecurityManager有关,但在这种情况下,你能指出具体的情况,为什么它不起作用?

我使用CGLib 3.1和3.2.0进行测试。

1 个答案:

答案 0 :(得分:2)

Cglib通过创建一个覆盖其超类的所有方法的子类来拦截方法。对于重写的package-private方法,必须在同一个包中定义子类。

SocketImpl不可能出于两个原因。 1.只允许引导类加载器在内部名称空间中定义包。 2.为了覆盖方法,运行时包也需要相等。但是,不可能将类注入引导类加载器。

使用cglib,这是不可能的。但是,您可以查看Byte Buddy,它允许通过检测创建引导类代理。