【问题标题】:Proxy in Java with a dynamic interface具有动态接口的 Java 代理
【发布时间】:2015-10-25 01:20:07
【问题描述】:

我正在尝试将一些 C# 代码移植到 Java,但在代理实现方面遇到了问题。

我有这门课:

public class Comic
{
    public int ComicID;

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

我正在尝试为该实体的特定方法调用添加一个拦截器,但我还需要访问它的字段,因为我将使用它们。

在寻找如何在 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);
}

问题是,type 是动态的,所以我不知道哪个会是动态的,而且我不希望代码具有所有接口的要求,所以我查找了如何@987654321 @:

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);
    }
}

然后我将它与代理一起使用:

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);
}

我得到的例外是

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

我查看了异常,但只找到了两个解决方案,即确保名称不与任何类型冲突(我确定不会)并使用 this.getClass().getClassLoader() 而不是 @ 987654332@(同样的错误)。

我做错了什么?

另一个问题是,如何获取“原始”对象,以便从 ComicID 等字段获取/设置值?使用上述代理方法,我可以很好地拦截方法,但我无法访问它的字段。

我已经阅读了here 以获取 InvocationHandler,但我不知道如何从处理程序中获取对象,也找不到使用它的示例。

【问题讨论】:

  • 不要把真正的问题埋在代码里。
  • 您实际上想在这里完成什么?很可能有一种更简单和/或预先存在的方法来处理它。
  • @chrylis 这是来自 C# 代码的端口,我生成原始对象的“副本”,继承原始对象,但增加了拦截任何方法调用的能力(例如用于记录或延迟加载)。现在想起来,我发现 Java 有一个动态代理构建器很好,但由于它只适用于接口,它与创建一个继承原始类的动态类不同......
  • @Daniichi 听起来您正在寻找的是 AspectJ 之类的东西,或者如果代理可以接受,则可能是 Spring AOP。 AspectJ 和基于 cglib 的 AOP 都可以使用实际的类,只要所讨论的类和方法不是最终的。

标签: java proxy


【解决方案1】:

只有一个类加载器可以看到你动态生成的界面,那就是 InterfaceLoader 加载器。您可以通过将它传递给 newProxyInstance 来消除错误。

但是,我敢肯定这对你没有任何好处。您正在编写的任何 java 代码都不会由该类加载器加载,因此您将无法通过该接口调用,除非通过反射。

如果您想使用代理,那么您必须让 Comic 实现一个接口,然后在任何地方使用该接口。在这种情况下,下一个问题的答案是将原始对象的一个​​实例传递给代理处理程序构造函数。

如果你真的想做这个动态拦截的事情,你可能想看看使用 ASM (http://asm.ow2.org/) 或 Javaassist 来构建一个覆盖你想要拦截的方法的 Comic 的动态子类,而不是使用代理.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多