简体   繁体   English

Java中的代理与动态接口

[英]Proxy in Java with a dynamic interface

I'm trying to port some C# code to Java and I'm having trouble with a proxy implementation. 我正在尝试将一些C#代码移植到Java而我在代理实现方面遇到了麻烦。

I have this class: 我有这门课:

public class Comic
{
    public int ComicID;

    private List<Volume> _volumes;
    public List<Volume> GetVolumes()
    {
        return _volumes;
    }
    public void SetVolumes(List<Volume> volumes)
    {
        _volumes = volumes;
    }
}

And I'm trying to add an interceptor to a specific Method call for this entity, but I also need access to it's fields since I'll be using them. 我正在尝试为此实体的特定方法调用添加拦截器,但我也需要访问它的字段,因为我将使用它们。

After looking around for how to implement proxies in Java, I got this: 在查看了如何在Java中实现代理之后,我得到了这个:

public void Load(Class<?> type)
{
    // - type is a Comic.class 

    ClassLoader appLoader = this.getClass().getClassLoader();

    MyProxyHandler proxyHandler = new MyProxyHandler();
    Object proxy = Proxy.newProxyInstance(appLoader, new Class[] { ComicInterface.class }, proxyHandler);
}

The problem is, the type is dynamic so I don't know which will be, and I don't want the code to have a requirement of having interfaces of everything, so I looked up on how to build a dynamic interface : 问题是, type是动态的,所以我不知道它会是什么,并且我不希望代码需要具有所有内容的接口,所以我查看了如何构建动态接口

public class InterfaceLoader extends ClassLoader
{
    public InterfaceLoader(ClassLoader loader)
    {
        super(loader);
    }

    public Class<?> GetInterface(Class<?> type) throws Exception
    {
        String interfaceName = type.getName() + "$Proxy";
        Class<?> interfaceType = null;
        interfaceType = findLoadedClass(interfaceName);
        if (interfaceType != null) { return interfaceType; }

        // - According to the link
        byte[] classData = new InterfaceBuilder().BuildInterface(interfaceName, type.getDeclaredMethods());
        return defineClass(interfaceName, classBytes, 0, classBytes.length);
    }
}

And then I'd use it with the Proxy: 然后我将它与代理一起使用:

public void Load(Class<?> type)
{
    // - type is a Comic.class 
    ClassLoader appLoader = this.getClass().getClassLoader();

    InterfaceLoader loader = new InterfaceLoader(appLoader);
    Class<?> dynamicInterface = loader.GetInterface(type);
    // - dynamicInterface on debug is "console.Comic$Proxy", seems fine

    MyProxyHandler proxyHandler = new MyProxyHandler();
    Object proxy = Proxy.newProxyInstance(appLoader, new Class[] { dynamicInterface }, proxyHandler);
}

The exception I get is 我得到的例外是

java.lang.IllegalArgumentException: interface console.Comic$Proxy is not visible from class loader

I've looked up the exception but only found two solutions, which is to make sure the name doesn't conflict with any type (and I'm sure it doesn't) and to use this.getClass().getClassLoader() instead of type.getClass().getClassLoader() (same error). 我查找了异常但只找到了两个解决方案,这是为了确保名称不与任何类型冲突(我确信它没有)并使用this.getClass().getClassLoader()而不是type.getClass().getClassLoader() (相同的错误)。

What am I doing wrong? 我究竟做错了什么?

And another issue is, how can I get the "original" object so I can get/set values from fields like ComicID ? 另一个问题是,如何获取“原始”对象,以便从ComicID等字段中获取/设置值? Using the above proxy method I can intercept methods fine, but I lose access to it's fields. 使用上面的代理方法我可以很好地拦截方法,但是我无法访问它的字段。

I've read about it here to get the InvocationHandler, but I don't know how to get the object from the handler and I couldn't find an example with it. 我在这里读到了它以获取InvocationHandler,但我不知道如何从处理程序中获取对象,我找不到它的示例。

There is only one classLoader that can see your dynamically generated interface, and that is the InterfaceLoader loader. 只有一个classLoader可以看到你动态生成的接口,那就是InterfaceLoader加载器。 You can probably make the error go away by passing that to newProxyInstance. 您可以通过将其传递给newProxyInstance来使错误消失。

But, I'm pretty sure this won't do you any good. 但是,我很确定这对你没有任何好处。 None of the java code you are writing is loaded by that class loader, so you won't be able to call through that interface except by reflection. 您正在编写的Java代码都不会被该类加载器加载,因此除了反射之外,您将无法通过该接口进行调用。

If you want to use a proxy, then you'll have to make Comic implement an interface, and then use that interface everywhere. 如果你想使用代理,那么你必须让Comic实现一个接口,然后在任何地方使用该接口。 In that case, the answer to your next question is that you would pass an instance of the original object to your proxy handler constructor. 在这种情况下,您的下一个问题的答案是您将原始对象的实例传递给您的代理处理程序构造函数。

If you really want to do this dynamic interception thing, you probably want to look at using ASM ( http://asm.ow2.org/ ) or Javaassist to build a dynamic subclass of Comic that overrides the method you want to intercept, instead of using a proxy. 如果你真的想要做这个动态拦截的事情,你可能想看看使用ASM( http://asm.ow2.org/ )或Javaassist来构建一个动态的Comic子类来覆盖你要拦截的方法,而不是使用代理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM