![](/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.