gpt4 book ai didi

java - 从 org.aspectj.lang.ProceedingJoinPoint 获取模板/通用 java.lang.reflect.Method 对象

转载 作者:行者123 更新时间:2023-11-30 05:57:47 27 4
gpt4 key购买 nike

如果 AspectJ 的工作方式与 EJB 拦截器的工作方式相同,这个问题就不会存在。

考虑 EJB 拦截器方式的基本场景:

@AroundInvoke
public Object log(final InvocationContext ctx) throws Exception {
// do stuff before
final Object result = ctx.proceed();
// do stuff after
return result;
}

现在我需要被拦截的 Method 对象。在这里我可以简单地这样做:

        Method method = ctx.getMethod();

就是这样,之后我将检查拦截方法的注释。

现在我正在使用部署到 servlet 容器 (Tomcat) 的应用程序,因此没有 EJB。其中AOP是使用Spring + AspectJ实现的。

around 方法如下所示:

@Around("execution(* foo.bar.domain.integration.database.dao..*(..))")
public Object log(final ProceedingJoinPoint pjp) throws Throwable {
// do stuff before
final Object result = pjp.proceed();
// do stuff after
return result;
}

在这里我不能再这样做:

Method method = pjp.getMethod(); // no such method exists

相反,我被迫使用反射自己获取 Method 对象,如下所示:

    final String methodName = pjp.getSignature().getName();
final Object[] arguments = pjp.getArgs();
final Class[] argumentTypes = getArgumentTypes(arguments);
final Method method = pjp.getTarget().getClass().getMethod(methodName, argumentTypes);

它一直有效,直到您想要掌握模板方法为止:

@Transactional
public <T extends Identifiable> T save(T t) {
if (null == t.getId()) {
create(t);
return t;
}
return update(t);
}

假设您按如下方式调用此方法:

Person person = new Person("Oleg");
personService.save(person);

您将收到:

Caused by: java.lang.NoSuchMethodException: foo.bar.domain.integration.database.dao.EntityService.save(foo.bar.domain.entity.Person)

抛出者:

pjp.getTarget().getClass().getMethod()

问题是泛型在运行时不存在,实际的方法签名是:

public Identifiable save(Identifiable t) {}

final Class[] argumentTypes 将包含一个元素,其类型将为 Person。所以这个调用:

pjp.getTarget().getClass().getMethod(methodName, argumentTypes);

查找方法:

save(Person p)

并且找不到它。

所以问题是:如何获取 java 的 template Method 对象的实例来表示已被拦截的确切方法?

我想其中一种方法是用蛮力的方式来做到这一点:获取参数父类(super class)/接口(interface),并尝试使用这些类型获取方法,直到不再得到 NoSuchMethodException,但这实在是丑陋。有没有一种正常的干净方法可以做到这一点?

最佳答案

好的,我的问题现在已经解决了。仔细一看后发现:methodSignature.getMethod()返回我注意到它返回的是接口(interface)而不是实现类,当然接口(interface)上没有注释。这与 EJB 拦截器不同,EJB 拦截器的 getMethod() 返回实现类方法。

所以最终的解决方案是这样的:

    final String methodName = pjp.getSignature().getName();
final MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
Method method = methodSignature.getMethod();
if (method.getDeclaringClass().isInterface()) {
method = pjp.getTarget().getClass().getDeclaredMethod(methodName, method.getParameterTypes());
}

如果您愿意,您也可以在需要时在这里处理接口(interface)注释。

还要注意这一点:method.getParameterTypes()如果没有这个,它仍然会抛出NoSuchMethodException,所以我们可以通过 ((MethodSignature)pjp.getSignature()).getMethod(); 获得正确的签名,这是一件好事。

希望不会再有什么意外,尽管我不喜欢在这里使用反射,但我只是更喜欢拥有实现类的方法实例,就像 EJB 的 InitationContext 中那样。

顺便说一句,Spring 的原生方法没有 AspectJ:

public Object invoke(final MethodInvocation invocation) throws Throwable {}

返回接口(interface)而不是实现类。为了长知识,也检查了一下。

最诚挚的问候和感谢您的帮助,我真的很感激。奥列格

关于java - 从 org.aspectj.lang.ProceedingJoinPoint 获取模板/通用 java.lang.reflect.Method 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5212088/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com