9

我正在使用 javassist 创建代理ProxyFactory。创建单个代理时一切正常。

但是,当我将代理对象传递给代理机制时,它会失败

javassist.bytecode.DuplicateMemberException:重复方法:com.mypackage.Bean_$$_javassist_0_$$_javassist_1 中的 setHandler

我正在用这个创建代理:

public Object createProxiedInstance(Object originalInstance) throws Exception {
    Class<?> originalClass = instance.getClass();
    ProxyFactory factory = new ProxyFactory();

    factory.setSuperclass(originalClass);

    factory.setHandler(new MethodHandler() {..});
    Class<T> proxyClass = factory.createClass();

    return proxyClass.newInstance();
}

那么,如何创建代理的代理?

更新:实际问题是每个代理都实现了ProxyObjectwhich definedsetHandler(..)方法。所以第二个代理正在尝试重新定义该方法,而不是在子类中覆盖它。

4

2 回答 2

4

问题是(实际上,它与 CGLIB 相同 - 我使用 commons-proxy 尝试过)我不应该尝试创建代理类的代理类。第二个代理应该再次属于原始类。因此,添加以下行可以解决问题:

if (instance instanceof ProxyObject) {
    originalClass = originalClass.getSuperclass();
}

还有一个建议——如果你可以使用某种拦截器(比如在 commons-proxy 中定义的拦截器),不要使用多个代理。

于 2010-04-12T21:19:59.337 回答
1

这是一个相当晚的答案,但您可能仍然有兴趣知道这一点:

Javassist 代理的实现相当幼稚。在您上面的代码中,Javassist 将始终使用以下方法创建一个代理类:

  1. 基类的任何可重写方法的方法
  2. (a) 获取代理处理程序 ( getHandler) 和 (b) 设置代理处理程序 ( setHandler)的两种方法

后两种方法的名称由 Javassist 硬编码并由ProxyObject接口表示。如果您现在创建代理类的代理类,Javassist 将安排ProxyObject两次创建 's 方法。一次符合第一个条件,一次符合第二个条件。

您可以通过设置 a 来避免这种情况,MethodFilter它指定不覆盖ProxyObject' 的方法,这样 javassist 只会根据第二个条件创建方法。但是,这意味着您不能再ProxyObject为超类代理设置 a ,而无需通过反射直接访问相应的字段。因此,您的方法可能是最干净的。

cglib 为每个类而不是每个实例定义回调,因此 cglib 的这个问题略有不同,但会导致另一个冲突。

但是,如果您想创建没有这些缺点的代理类,您可能会对我的库Byte Buddy感兴趣,这是我在使用 cglib 和 javassist 在极端情况下工作时感到沮丧之后编写的。如果您正在使用运行时代码生成,我希望它可以帮助您提供一些其他库所缺乏的灵活性。

于 2014-05-03T14:33:35.837 回答