1. 前言
项目是一个比较古老的项目, 在根据需求修改了一些功能之后, 提交代码, 更新部署, 然后点击某个功能, 报错:
java.lang.NoSuchMethodError: com.xxx.xxx.dao.XxxDao.xxx; at xxxx at xxxx at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621) at xxxx at xxxx at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:607) at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:892) at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294) at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68) at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117) at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108) at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370) at ognl.ASTMethod.getValueBody(ASTMethod.java:91) at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) at ognl.SimpleNode.getValue(SimpleNode.java:258) at ognl.Ognl.getValue(Ognl.java:467) at ognl.Ognl.getValue(Ognl.java:431)
然后当时思路有点问题, 没有直接去考虑这个类中有没有这个方法, 而是考虑的比较复杂了, 会不会是类加载的问题, 因为这个项目比较古老, 项目本身是jdk1.7, 但是里面甚至还包含了用jdk1.6编译出来的class和jar包等.当时想的可能是类加载器加载问题,是不是加载到了同路径同名的另一个class, 也可能是编译版本太低导致不兼容等.
2. 初步调试
首先进入arthas, 因为是跑在tomcat中的war包项目, 所以当想要使用dump命令或者jad命令的时候, 会提示有多个类, 需要选择其中一个查看, 但是离谱的是类的HASHCODE竟然没有, 是空的- -, 所以必须要从类加载器方面来过了, 但是离谱的是CLASSLOADER竟然也是空的(如下图)…
所以需要想先想办法区分这几个类, 想来想去还是先从类加载器入手, 先找到目标项目的类加载器的名称和HashCode. 不然这里面别的项目同包名同名称的类会干扰我排查问题, 想到使用classloader -l命令列出类加载器列表, 好在天不亡我, 虽然没有类加载器名称, 但是找到了它们的hashcode(如下图)
然后查了一下文档, 发现可以使用 -r去查找类加载器的资源路径, 而且刚好可以使用-c指定类加载器的hashcode, 这也顺便把项目路径查出来了, 所以锁定了类加载器所对应的项目是哪一个(如下图)
3. 解决问题
然后我看到这个jar包路径的时候突然想到, 我先不继续排查类加载器的问题(因为这方面很少有问题, 如果不自定义类加载器乱搞的话, 并且如果真是这方面问题估计一时半会也解决不了), 我先跑去瞅瞅这类里面到底有没有这方法, 所以把这个jar包下载下来之后拖到idea里一看……………………………………
果然没有那个方法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
然后一看jar包里面class的修改时间……………….半年以前。
行吧你赢了。
重新编译这个依赖jar包, 更新部署, 问题解决。