用于创建抽象类(而不是接口)的代理的 java.lang.rect.Proxy 的替代品

根据 文件:

[ 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
49764 次浏览

What you can do in such a case is having a proxy handler that will redirect calls to existing methods of your abstract class.

You of course will have to code it, however it's quite simple. For creating your Proxy, you'll have to give him an InvocationHandler. You'll then only have to check the method type in the invoke(..) method of your invocation handler. But beware : you'll have to check the method type against the underlying object associated to your handler, and not against the declared type of your abstract class.

If I take as an example your dog class, your invocation handler's invoke method may look like this (with an existing associated dog subclass called .. well ... 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 ?
}
}

However, there is something that keep me wondering : I've talked about a dog object. But, as the Dog class is abstract, you can't create instances, so you have existing subclasses. Furthermore, as a rigorous inspection of Proxy source code reveals, you may discover (at Proxy.java:362) that it is not possible to create a Proxy for a Class object that does not represents an interface).

So, apart from the reality, what you want to do is perfectly possible.

It can be done using Javassist (see ProxyFactory) or CGLIB.

Adam's example using Javassist:

I (Adam Paynter) wrote this code using 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();

Which produces this output:

Woof!
Handling public abstract void mock.Dog.fetch() via the method handler