处理 AOP 反射代理:"object is not an instance of declaring class"
Handling AOP reflective proxies: "object is not an instance of declaring class"
我的应用程序需要对 Spring bean 执行动态调用。我扫描一个 Spring bean 以查找使用自定义注释注释的方法,并存储对 Method
object 的引用以供将来调用。
public Method getMethod(Class<?> clazz, final String name) throws ReflectiveOperationException, NoSuchMethodException
{
Method meth = null;
for (Method m : clazz.getMethods())
{
String alias;
WorkflowMethod annotation = m.getAnnotation(WorkflowMethod.class);
if (annotation == null)
{
log.warn(...);
continue;
}
alias = annotation.alias();
if (StringUtils.isEmpty(alias))
alias = m.getName();
if (!name.equals(alias))
continue;
if (meth != null)
throw new Exception(...);
meth = m;
}
if (meth == null)
throw new NoSuchMethodException(...);
return meth;
}
以上代码将根据没有重载的事实(按要求)按名称提取方法。
但是,当我稍后在代码中尝试调用 meth.invoke(springBean,params)
时,我得到了标题中描述的 InvocationTargetException
。
我所有的 bean 都是 AOP 代理,因为我使用 Spring 个事务。
我使用以下代码获取 clazz
变量,因为 AOP 代理不显示来自源 class
的注释
Class<?> managerClass;
if (workflowManager instanceof TargetClassAware)
managerClass = ((TargetClassAware) workflowManager).getTargetClass();
else
managerClass = workflowManager.getClass();
总而言之,我需要使用 TargetClassAware
,否则我将无法扫描注释,但如果我从原始 class 获得方法,它将与代理 class.
如何正确调用方法?
在我写问题的过程中,我自己找到了答案。
我的想法是对的:我不能扫描AOP代理,否则我不能得到注解,但是我必须选择不是来自原始class 而是来自代理的方法本身.
方法如下:扫描目标 class 以查找带注释的方法,然后从代理 class 中选择相同的方法(相同的名称和参数)。代码有两种修改方式,这里是一种:
public Method getMethod(Class<?> targetClass, Class<?> proxyClass, final String name) throws ReflectiveOperationException, NoSuchMethodException
{
Method meth = null;
for (Method m : targetClass.getMethods())
{
String alias;
WorkflowMethod annotation = m.getAnnotation(WorkflowMethod.class);
if (annotation == null)
{
log.warn("...);
continue;
}
alias = annotation.alias();
if (StringUtils.isEmpty(alias))
alias = m.getName();
if (!name.equals(alias))
continue;
if (meth != null)
throw new Exception(...);
if (proxyClass == null)
meth = m;
else
meth = proxyClass.getMethod(m.getName(), m.getParameterTypes());
}
if (meth == null)
throw new NoSuchMethodException(...);
return meth;
}
也可以修改代码以从 getMethod
中检查 TargetClassAware
,而无需使用 2 个参数
我的应用程序需要对 Spring bean 执行动态调用。我扫描一个 Spring bean 以查找使用自定义注释注释的方法,并存储对 Method
object 的引用以供将来调用。
public Method getMethod(Class<?> clazz, final String name) throws ReflectiveOperationException, NoSuchMethodException
{
Method meth = null;
for (Method m : clazz.getMethods())
{
String alias;
WorkflowMethod annotation = m.getAnnotation(WorkflowMethod.class);
if (annotation == null)
{
log.warn(...);
continue;
}
alias = annotation.alias();
if (StringUtils.isEmpty(alias))
alias = m.getName();
if (!name.equals(alias))
continue;
if (meth != null)
throw new Exception(...);
meth = m;
}
if (meth == null)
throw new NoSuchMethodException(...);
return meth;
}
以上代码将根据没有重载的事实(按要求)按名称提取方法。
但是,当我稍后在代码中尝试调用 meth.invoke(springBean,params)
时,我得到了标题中描述的 InvocationTargetException
。
我所有的 bean 都是 AOP 代理,因为我使用 Spring 个事务。
我使用以下代码获取 clazz
变量,因为 AOP 代理不显示来自源 class
Class<?> managerClass;
if (workflowManager instanceof TargetClassAware)
managerClass = ((TargetClassAware) workflowManager).getTargetClass();
else
managerClass = workflowManager.getClass();
总而言之,我需要使用 TargetClassAware
,否则我将无法扫描注释,但如果我从原始 class 获得方法,它将与代理 class.
如何正确调用方法?
在我写问题的过程中,我自己找到了答案。
我的想法是对的:我不能扫描AOP代理,否则我不能得到注解,但是我必须选择不是来自原始class 而是来自代理的方法本身.
方法如下:扫描目标 class 以查找带注释的方法,然后从代理 class 中选择相同的方法(相同的名称和参数)。代码有两种修改方式,这里是一种:
public Method getMethod(Class<?> targetClass, Class<?> proxyClass, final String name) throws ReflectiveOperationException, NoSuchMethodException
{
Method meth = null;
for (Method m : targetClass.getMethods())
{
String alias;
WorkflowMethod annotation = m.getAnnotation(WorkflowMethod.class);
if (annotation == null)
{
log.warn("...);
continue;
}
alias = annotation.alias();
if (StringUtils.isEmpty(alias))
alias = m.getName();
if (!name.equals(alias))
continue;
if (meth != null)
throw new Exception(...);
if (proxyClass == null)
meth = m;
else
meth = proxyClass.getMethod(m.getName(), m.getParameterTypes());
}
if (meth == null)
throw new NoSuchMethodException(...);
return meth;
}
也可以修改代码以从 getMethod
中检查 TargetClassAware
,而无需使用 2 个参数