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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3344299/
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 22:28:12  来源:igfitidea点击:

How do I get the underlying type of a proxy object in java?

javaproxy

提问by blank

I'd like to access the classname of the underlying class which is an instance of java.lang.reflect.Proxy.

我想访问底层类的类名,它是java.lang.reflect.Proxy.

Is this possible?

这可能吗?

采纳答案by Bozho

You can get the InvocationHandlerwith which the proxy was created, by calling Proxy.getInvocationHandler(proxy)

您可以InvocationHandler通过调用获取创建代理的Proxy.getInvocationHandler(proxy)

Note that in the case of java.lang.reflect.Proxythere is no underlying classper se. The proxy is defined by:

请注意,在这种情况下,本身java.lang.reflect.Proxy没有基础类。代理定义为:

  • interface(s)
  • invocation handler
  • 接口
  • 调用处理程序

And the wrapped class is usually passed to the concrete invocation handler.

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

回答by Stephen C

Well a Proxy instance won't be an instance of java.lang.reflect.Proxyper se. Rather, it will be an instance of a subclassof java.lang.reflect.Proxy.

那么 Proxy 实例java.lang.reflect.Proxy本身不会是一个实例。相反,这将是一个实例子类java.lang.reflect.Proxy

Anyway, the way to get the actual proxy classes name is:

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

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

However, you cannot get the name of the class that the Proxy is a proxy for, because:

但是,您无法获得 Proxy 为其代理的类的名称,因为:

  1. you proxy interfaces not classes, and
  2. a Proxy can be a proxy for multiple interfaces
  1. 你代理接口而不是类,并且
  2. 一个代理可以是多个接口的代理

However, from looking at the source code of the ProxyGeneratorclass, it seems that the interfaces are recorded in the generated proxy class as the interfaces of the class. So you should be able to get them at runtime via the proxy classes Classobject; e.g.

但是从ProxyGenerator类的源码看,好像接口是记录在生成的代理类中的,作为类的接口。所以你应该能够在运行时通过代理类Class对象获取它们;例如

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

(Note: I've not tried this ...)

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

回答by Sllouyssgort

I found a good solution on this site(now archived):

我在这个网站上找到了一个很好的解决方案(现已存档):

@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
  }
}

Usage

用法

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

回答by lboix

Here was the solution we used with my team (we need the name of the class behind the proxy) :

这是我们与我的团队一起使用的解决方案(我们需要代理后面的类的名称):

if (getTargetName(yourBean) ... ) {

}

With this little helper :

有了这个小帮手:

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

Hope it helps!

希望能帮助到你!

回答by Przemek Nowak

You can use the following code for retrieve the info (ArrayUtils is from Apache commons lang) about invocation handler and the interfaces of the current proxy:

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

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

Example result:

结果示例:

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

回答by 18446744073709551615

First of all, java.lang.reflect.Proxyworks only on interfaces. The framework creates a descendant class that implements the interface(s) but extends java.lang.reflect.Proxy rather than an application class that may be of interest to you. There is no inheritance of multiple classes in modern (2016) Java.

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

In my case, the debugger shows that the object of interest is in the objfield in the invocation handler of the proxy object.

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

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

You will have to catch()two exceptions: NoSuchFieldExceptionand IllegalAccessException.

您将有catch()两个例外:NoSuchFieldExceptionIllegalAccessException

I found it useful to print the list of fields of declared fields from the catch()clause:

我发现打印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+ ";");
    }
...
}

Note that different frameworks use different proxies and even different techniques of proxying. The solution that worked for me may be not applicable in your case. (It definitely will not work for Javassist or Hibernate proxies.)

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

回答by winne2

Simple and robust:

简单而强大:

AopUtils.getTargetClass(object).getName(); 

Will also work for CGLIB proxies and non-proxy objects.

也适用于 CGLIB 代理和非代理对象。