##关于 Spring AOP 中,包含参数的成员方法的调用,出现 NoSuchMethodException 的研究
网上看了一大堆,大都是关于init方法和构造方法的情况,可能此处有些特殊。
发出来交流一下。
Spring版本 - spring-framework-2.5.6-with-dependencies
在使用中,偶然用到一个单独的有参数的方法的调用,包了错误 NoSuchMethodException
首先不是修饰符的问题 - 因为内部有暴力访问机制 源码 ——
package org.springframework.util;
public abstract class ReflectionUtils
/**
* Make the given method accessible, explicitly setting it accessible if necessary.
* The <code>setAccessible(true)</code> method is only called when actually necessary,
* to avoid unnecessary conflicts with a JVM SecurityManager (if active).
* @param method the method to make accessible
* @see java.lang.reflect.Method#setAccessible
*/
public static void makeAccessible(Method method) {
if (!Modifier.isPublic(method.getModifiers()) ||
!Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
method.setAccessible(true);
}
}
在Spring的AOP中会自动完成方法的切入点表达式的匹配
mi Cglib2AopProxy$CglibMethodInvocation (id=131)
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(insert)
相关的关键生成类
package org.springframework.aop.aspectj;
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor
/**
* Return the ProceedingJoinPoint for the current invocation,
* instantiating it lazily if it hasn't been bound to the thread already.
* @param rmi the current Spring AOP ReflectiveMethodInvocation,
* which we'll use for attribute binding
* @return the ProceedingJoinPoint to make available to advice methods
*/
protected ProceedingJoinPoint lazyGetProceedingJoinPoint(ProxyMethodInvocation rmi) {
return new MethodInvocationProceedingJoinPoint(rmi);
}
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(insert)
后期会在此处使用
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
[org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(insert)]
Object[] actualArgs = args;
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
java.lang.reflect.InvocationTargetException
throw ex.getTargetException();
}
}
最终可能出现报错的产出位置
package org.springframework.aop.aspectj;
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}
重点看pmi 与pjp
解决办法 -
由于这种机制的存在,主要是引起通知方法的调用和匹配
在其内部,获取有参方法会先匹配切入点 而切入点的自动生成机制比较简单 例如
本应该是
...insert(java.lang.String); target is of class ...
结果生成的切入点表达式为
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint: execution(insert)
那么,在此处,无参的方法为了使用是必须出现的
但是如果本身并不需要调用的话,那么就没有什么意义
如同AOP的注解中定义的切入点表达式一般,并无任何意义,方法体不调用,是不会执行的。 只是避免了内部机制实现的报错而已。
由于当前项目配置较为驳杂,后期有空单独把这一部分抽取出来进行测试研究,如有更好的见解,欢迎评论交流。
如需要转载 请注明文章出处 https://my.oschina.net/u/3032872/blog/1648360 谢谢~