如何在java中获取代理对象的基础类型?

时间:2010-07-27 13:50:14

标签: java proxy

我想访问作为java.lang.reflect.Proxy实例的基础类的类名。

这可能吗?

8 个答案:

答案 0 :(得分:23)

您可以致电InvocationHandler

获取创建代理的Proxy.getInvocationHandler(proxy)

请注意,在java.lang.reflect.Proxy的情况下,本身没有基础类。代理由以下人员定义:

  • 接口(S)
  • 调用处理程序

包装类通常传递给具体的调用处理程序。

答案 1 :(得分:20)

我在this site(现已归档)找到了一个很好的解决方案:

@SuppressWarnings({"unchecked"})
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
  if (AopUtils.isJdkDynamicProxy(proxy)) {
    return (T) ((Advised)proxy).getTargetSource().getTarget();
  } else {
    return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
  }
}

用法

@Override
protected void onSetUp() throws Exception {
  getTargetObject(fooBean, FooBeanImpl.class).setBarRepository(new MyStubBarRepository());
}

答案 2 :(得分:15)

代理实例本身不是java.lang.reflect.Proxy 的实例。相反,它将是java.lang.reflect.Proxy子类的实例。

无论如何,获取实际代理类名称的方法是:

Proxy proxy = ...
System.err.println("Proxy class name is " + proxy.getClass().getCanonicalName());

但是,您无法获取Proxy所代表的类的名称,因为:

  1. 您代理接口而不是类,
  2. 代理可以是多个接口的代理
  3. 但是,通过查看ProxyGenerator类的源代码,似乎接口被记录在生成的代理类中作为类的接口。所以你应该能够通过代理类Class对象在运行时获取它们; e.g。

    Class<?>[] classes = proxy.getClass().getInterfaces();
    

    (注意:我没试过这个......)

答案 3 :(得分:5)

以下是我们团队使用的解决方案(我们需要代理背后的类名称):

if (getTargetName(yourBean) ... ) {

}

有了这个小帮手:

private String getTargetName(final Object target) {

    if (target == null) {
        return "";
    }

    if (targetClassIsProxied(target)) {

        Advised advised = (Advised) target;

        try {

            return advised.getTargetSource().getTarget().getClass().getCanonicalName();
        } catch (Exception e) {

            return "";
        }
    }

    return target.getClass().getCanonicalName();
}

private boolean targetClassIsProxied(final Object target) {

    return target.getClass().getCanonicalName().contains("$Proxy");
}

希望它有所帮助!

答案 4 :(得分:3)

您可以使用以下代码检索有关调用处理程序和当前代理的接口的信息(ArrayUtils来自Apache commons lang):

String.format("[ProxyInvocationHandler: %s, Interfaces: %s]", 
     Proxy.getInvocationHandler(proxy).getClass().getSimpleName(), 
     ArrayUtils.toString(proxy.getClass().getInterfaces()));

示例结果:

[ProxyInvocationHandler: ExecuteProxyChain, Interfaces: {interface com.example.api.CustomerApi}]}

答案 5 :(得分:0)

首先,java.lang.reflect.Proxy仅适用于接口。该框架创建了一个实现接口的后代类,但扩展了java.lang.reflect.Proxy而不是您可能感兴趣的应用程序类。现代(2016)Java中没有多个类的继承。

在我的例子中,调试器显示感兴趣的对象位于代理对象的调用处理程序中的obj字段中。

    Object handler = Proxy.getInvocationHandler(somethingProxied);
    Class handlerClass = handler.getClass();
    Field objField = handlerClass.getDeclaredField("obj");
    objField.setAccessible(true);
    Object behindProxy = objField.get(handler);

您必须catch()两个例外:NoSuchFieldExceptionIllegalAccessException

我发现从catch()子句打印声明字段的字段列表很有用:

...
} catch (NoSuchFieldException nsfe) {
    nsfe.printStackTrace();

    Object handler = Proxy.getInvocationHandler(somethingProxied);
    Class handlerClass = handler.getClass();
    for (Field f : handlerClass.getDeclaredFields()) {
        f.setAccessible(true);
        String classAndValue = null;
        try {
            Object v = f.get(handler);
            classAndValue= "" + (v == null ? "" : v.getClass()) + " : " + v;
        } catch (IllegalAccessException iae) {
            iae.printStackTrace();
        }
        System.out.println(" field: " + f.getName() + " = " + classAndValue+ ";");
    }
...
}

请注意,不同的框架使用不同的代理甚至不同的代理技术。对我有用的解决方案可能不适用于您的情况。 (它肯定不适用于Javassist或Hibernate代理。)

答案 6 :(得分:0)

简单而强大:

AopUtils.getTargetClass(object).getName(); 

还将适用于CGLIB代理和非代理对象。

答案 7 :(得分:0)

静态 Hibernate.getClass() 在这种情况下可能很有用。

Get the true, underlying class of a proxied persistent class

    public static Class getClass(Object proxy) {
        if ( proxy instanceof HibernateProxy ) {
            return ( ( HibernateProxy ) proxy ).getHibernateLazyInitializer()
                    .getImplementation()
                    .getClass();
        }
        else {
            return proxy.getClass();
        }
    }