spring aop报Mismatch on arguments to advice method错误问题

来源:互联网 发布:linux 查找文件夹大小 编辑:程序博客网 时间:2024/05/21 23:49

在项目中用到spring的aop功能,总昨天开始发现每次执行apo的pointcut的时候,都会报这样的错误:

org.springframework.aop.AopInvocationException: Mismatch on arguments to advice method [public void com.service.impl.LogServiceImpl.logArg(org.aspectj.lang.JoinPoint)]; pointcut expression [org.aspectj.weaver.internal.tools.PointcutExpressionImpl@95215b]; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring classCaused by: java.lang.IllegalArgumentException: object is not an instance of declaring classat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:597)at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:576)at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:45)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)at $Proxy6.createPlanTaskTemplete(Unknown Source)at service.TestPlanTask.testCreatePlanTaskTemplete(TestPlanTask.java:31)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)at java.lang.reflect.Method.invoke(Method.java:597)at junit.framework.TestCase.runTest(TestCase.java:168)at junit.framework.TestCase.runBare(TestCase.java:134)at junit.framework.TestResult$1.protect(TestResult.java:110)at junit.framework.TestResult.runProtected(TestResult.java:128)at junit.framework.TestResult.run(TestResult.java:113)at junit.framework.TestCase.run(TestCase.java:124)at junit.framework.TestSuite.runTest(TestSuite.java:232)at junit.framework.TestSuite.run(TestSuite.java:227)at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
试了各种方法都不行,除非注释掉aop。昨天搞了一晚上都没好,很是郁闷。

今天上午突然想起,前天替换了一些lib 包,于是找找被替换的包,在回收站里面,居然还在,还好我有不喜欢清理的坏习惯。把被替换的包重新导回来,发现可以用了。于是我把每一个被替换的都重新替换一次,最后发现是spring.jar出了问题,其实早就应该想到的。一直以为aspectJ出了问题。

用工具把两个包打开,发现可以用的是2.0版本,出问题的是2.0.8版本。

根据堆栈信息定位到,org.springframework.aop.aspectj.AbstractAspectJAdvice类的invokeAdviceMethodWithGivenArgs()方法。两个版本的方法大致是相同的,

  protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {    Object[] actualArgs = args;    if (this.aspectJAdviceMethod.getParameterTypes().length == 0)      actualArgs = null;    try    {      if ((!Modifier.isPublic(this.aspectJAdviceMethod.getModifiers())) || (!Modifier.isPublic(this.aspectJAdviceMethod.getDeclaringClass().getModifiers())))      {        this.aspectJAdviceMethod.setAccessible(true);      }      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)    {    }    throw ex.getTargetException();  }
可以很明显看到异常是因为return语句的invoke执行异常抛出的,这里的invoke()方法就是jdk中反射机制中的,也就是说问题出在参数actualArgs利用反射机制注入的过程中类型不匹配造成的。

利用debug看到两个版本的actualArgs参数对象,下面是2.0版本


下面是2.0.8版本



发现参数对象数组只有一个元素,就是MethodInvocationProceedingJoinPoint的对象,2.0版本的属性arguments有两个参数,当然了,这是aop代理的pointcut中方法的参数。但是在2.0.8版本中参数却为空。我想导致发生错误的原因就是这个MethodInvocationProceedingJoinPoint对象的问题。

在看一下这个对象是怎么产生的,定位到同类下的方法currentJoinPoint()

2.0版本

public static JoinPoint currentJoinPoint()  {    ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation)ExposeInvocationInterceptor.currentInvocation();    JoinPoint jp = (JoinPoint)rmi.getUserAttribute(JOIN_POINT_KEY);    if (jp == null) {      jp = new MethodInvocationProceedingJoinPoint(rmi);      rmi.setUserAttribute(JOIN_POINT_KEY, jp);    }    return jp;  }


2.0.8版本

public static JoinPoint currentJoinPoint()  {    MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();    if (!(mi instanceof ProxyMethodInvocation)) {      throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);    }    ProxyMethodInvocation pmi = (ProxyMethodInvocation)mi;    JoinPoint jp = (JoinPoint)pmi.getUserAttribute(JOIN_POINT_KEY);    if (jp == null) {      jp = new MethodInvocationProceedingJoinPoint(pmi);      pmi.setUserAttribute(JOIN_POINT_KEY, jp);    }    return jp;  }

发现两个版本的实现机制不同,第一个事采用反射机制,第二个采用的是代理机制。由于本人水平有限,源代码就没有继续向下解析,我想造成错误的原因应该就是两种机制不同而引起的jp对象不同,至于根本原因,等有时间继续向下解析吧。如果有高手和前辈知道具体原因的,请留言告知,万分感谢。

原创粉丝点击