处理AOP反射代理:"对象不是声明类的实例"

时间:2015-07-09 08:50:21

标签: java spring dynamic-proxy

我的应用程序需要在Spring bean上执行动态调用。我扫描Spring bean以获取使用自定义注释注释的方法,并将对Method对象的引用存储起来以供将来调用。

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 Transactions。

我使用以下代码获取clazz变量,因为AOP代理不会显示来自源类的注释

    Class<?> managerClass;
    if (workflowManager instanceof TargetClassAware)
        managerClass = ((TargetClassAware) workflowManager).getTargetClass();
    else
        managerClass = workflowManager.getClass();

总结一下,我需要使用TargetClassAware,否则我将无法扫描注释,但如果我从原始类中获取方法,则它将与代理类不兼容。

如何正确调用方法?

1 个答案:

答案 0 :(得分:0)

在我写这个问题时,我自己找到了答案。

我的想法是对的:我无法扫描AOP代理,否则我无法获得注释,但是我必须选择的方法不是来自原始类,而是来自代理本身

方法如下:扫描目标类以获取带注释的方法,然后从代理类中选择相同的方法(相同的名称和参数)。代码可以通过两种方式修改,这里有一个:

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

也可以修改代码以在TargetClassAware内检查getMethod,而无需使用2个参数