如何在java中获取代理对象的基础类型?
我想访问底层类的类名,它是java.lang.reflect.Proxy
一个实例。
这可能吗?
您可以通过调用Proxy.getInvocationHandler(proxy)
来获取创建代理的InvocationHandler
请注意,在java.lang.reflect.Proxy
的情况下,本身没有底层类 。 代理定义如下:
- 接口(S)
- 调用处理程序
并且包装的类通常被传递给具体的调用处理程序。
我在这个网站上找到了一个很好的解决方案(现已存档):
@SuppressWarnings({"unchecked"}) protected T getTargetObject(Object proxy, Class 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()); }
那么,Proxy实例本身不是java.lang.reflect.Proxy
的实例。 相反,它将是java.lang.reflect.Proxy
的子类的实例。
无论如何,获取实际代理类名称的方法是:
Proxy proxy = ... System.err.println("Proxy class name is " + proxy.getClass().getCanonicalName());
但是,您无法获取Proxy所代表的类的名称,因为:
- 代理接口而不是类,和
- 代理可以是多个接口的代理
但是,通过查看ProxyGenerator
类的源代码,似乎接口被记录在生成的代理类中作为类的接口。 所以你应该能够通过代理类Class
对象在运行时获取它们; 例如
Class>[] classes = proxy.getClass().getInterfaces();
(注意:我没试过这个…)
这是我们与团队一起使用的解决方案(我们需要代理背后的类名称):
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"); }
希望能帮助到你!
您可以使用以下代码检索有关调用处理程序和当前代理的接口的信息(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}]}
首先, java.lang.reflect.Proxy
仅适用于接口。 该框架创建了一个实现接口的后代类,但扩展了java.lang.reflect.Proxy而不是您可能感兴趣的应用程序类。 现代(2016)Java中没有多个类的inheritance。
在我的例子中,调试器显示感兴趣的obj
位于代理对象的调用处理程序中的obj
字段中。
Object handler = Proxy.getInvocationHandler(somethingProxied); Class handlerClass = handler.getClass(); Field objField = handlerClass.getDeclaredField("obj"); objField.setAccessible(true); Object behindProxy = objField.get(handler);
您将必须catch()
两个exception: NoSuchFieldException
和IllegalAccessException
。
我发现从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代理。)