98

根据文档

[ java.lang.reflect.]Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

newProxyMethod方法(负责生成动态代理)具有以下签名:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

不幸的是,这阻止了生成扩展特定抽象类(而不是实现特定接口)的动态代理。这是有道理的,考虑到java.lang.reflect.Proxy“所有动态代理的超类”,从而防止另一个类成为超类。

因此,是否有任何替代方案java.lang.reflect.Proxy可以生成从特定抽象类继承的动态代理,将对抽象方法的所有调用重定向到调用处理程序?

例如,假设我有一个抽象类Dog

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

有没有一门课可以让我做以下事情?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); // Will be handled by the invocation handler
dog.bark();  // Will NOT be handled by the invocation handler
4

2 回答 2

131

可以使用Javassist(参见参考资料ProxyFactory)或CGLIB来完成。

Adam 使用 Javassist 的示例:

我(Adam Paynter)使用 Javassist 编写了这段代码:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
    new MethodFilter() {
        @Override
        public boolean isHandled(Method method) {
            return Modifier.isAbstract(method.getModifiers());
        }
    }
);

MethodHandler handler = new MethodHandler() {
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        System.out.println("Handling " + thisMethod + " via the method handler");
        return null;
    }
};

Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();

产生这个输出:

纬!
通过方法处理程序处理 public abstract void mock.Dog.fetch()
于 2010-07-20T16:32:23.273 回答
-9

在这种情况下,您可以做的是拥有一个代理处理程序,它将调用重定向到抽象类的现有方法。

您当然必须对其进行编码,但这很简单。为了创建您的代理,您必须给他一个InvocationHandler. 然后,您只需检查invoke(..)调用处理程序方法中的方法类型。但请注意:您必须对照与处理程序关联的底层对象检查方法类型,而不是对照抽象类的声明类型。

如果我以您的狗类为例,您的调用处理程序的调用方法可能看起来像这样(现有关联的狗子类称为 .. 嗯 ... dog

public void invoke(Object proxy, Method method, Object[] args) {
    if(!Modifier.isAbstract(method.getModifiers())) {
        method.invoke(dog, args); // with the correct exception handling
    } else {
        // what can we do with abstract methods ?
    }
}

然而,有一些事情让我想知道:我谈到了一个dog对象。但是,由于 Dog 类是抽象的,您不能创建实例,因此您有现有的子类。此外,正如对 Proxy 源代码的严格检查所揭示的那样,您可能会发现(在 Proxy.java:362 处)不可能为不代表接口的 Class 对象创建代理)。

所以,抛开现实,你想做的事是完全有可能的。

于 2010-07-20T15:46:04.810 回答