![](/img/trans.png)
[英]How to resolve java.lang.ClassNotFoundException: org.aspectj.lang.ProceedingJoinPoint exception?
[英]Getting a Template/Generic java.lang.reflect.Method object from org.aspectj.lang.ProceedingJoinPoint
如果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("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 [] argumentsTypes将包含一个元素,其类型为Person。 所以这个电话:
pjp.getTarget().getClass().getMethod(methodName, argumentTypes);
将查找方法:
save(Person p)
并且不会找到它。
所以问题是:如何获取java的模板方法对象的实例,该对象表示已被拦截的确切方法?
我猜想其中一种方法是蛮力的:获取参数超类/接口,并尝试使用这些类型获取方法,直到不再获取NoSuchMethodException为止,但这很丑陋。 有正常的清洁方法可以做到吗?
好吧,现在我的问题解决了。 仔细研究一下:methodSignature.getMethod()返回后,我注意到它返回了接口,而不是实现类,并且接口上当然没有注释。 这与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());
}
如果需要,还可以在此处处理接口注释。
还要注意这一点:method.getParameterTypes()如果没有此设置,它仍然会引发NoSuchMethodException,因此,我们可以通过((MethodSignature)pjp.getSignature())。getMethod();获得正确的签名是一件好事。
希望没有更多的惊喜,即使我对在这里使用反射不满意,我也更喜欢拥有实现类的方法实例,就像在EJB的InvocationContext中一样。
BTW,Spring没有AspectJ的本机方法:
public Object invoke(final MethodInvocation invocation) throws Throwable {}
返回接口并且不实现类。 也为了知识而对其进行了检查。
最好的问候,并感谢您的帮助,我真的很感激。 奥列格
MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
Method targetMethod = methodSignature.getMethod();
这不是应该立即归咎于API。
另请参见Spring AOP:如何获取所建议方法的注释 。 我自己还没有测试过。 那里的OP说它为他解决了这个问题。 对于其他用途,需要额外的@Around(annotation...)
注释。 (例如,尝试将目标设置为仅METHOD
,并查看其行为)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.