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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3291637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 21:45:59  来源:igfitidea点击:

Alternatives to java.lang.reflect.Proxy for creating proxies of abstract classes (rather than interfaces)

javadynamic-proxy

提问by Adam Paynter

According to the documentation:

根据文档

[java.lang.reflect.]Proxyprovides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

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

The newProxyMethodmethod(responsible for generating the dynamic proxies) has the following signature:

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

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

Unfortunately, this prevents one from generating a dynamic proxy that extendsa specific abstract class (rather than implementingspecific interfaces). This makes sense, considering java.lang.reflect.Proxyis "the superclass of all dynamic proxies", thereby preventing another class from being the superclass.

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

Therefore, are there any alternatives to java.lang.reflect.Proxythat can generate dynamic proxies that inheritfrom a specific abstract class, redirecting all calls to the abstractmethods to the invocation handler?

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

For example, suppose I have an abstract class Dog:

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

public abstract class Dog {

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

    public abstract void fetch();

}

Is there a class that allows me to do the following?

是否有一个课程允许我执行以下操作?

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

采纳答案by axtavt

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

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

Adam's example using Javassist:

Adam 使用 Javassist 的示例:

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

Which produces this output:

产生这个输出:

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

回答by Riduidel

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.

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

If I take as an example your dog class, your invocation handler's invoke method maylook like this (with an existing associated dog subclass called .. well ... dog)

如果我以您的狗类为例,则您的调用处理程序的 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 ?
    }
}

However, there is something that keep me wondering : I've talked about a dogobject. 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).

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

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

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