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竟然也是空的(如下图)…

Untitled

所以需要想先想办法区分这几个类, 想来想去还是先从类加载器入手, 先找到目标项目的类加载器的名称和HashCode. 不然这里面别的项目同包名同名称的类会干扰我排查问题, 想到使用classloader -l命令列出类加载器列表, 好在天不亡我, 虽然没有类加载器名称, 但是找到了它们的hashcode(如下图)

Untitled

然后查了一下文档, 发现可以使用 -r去查找类加载器的资源路径, 而且刚好可以使用-c指定类加载器的hashcode, 这也顺便把项目路径查出来了, 所以锁定了类加载器所对应的项目是哪一个(如下图)

Untitled

3. 解决问题

然后我看到这个jar包路径的时候突然想到, 我先不继续排查类加载器的问题(因为这方面很少有问题, 如果不自定义类加载器乱搞的话, 并且如果真是这方面问题估计一时半会也解决不了), 我先跑去瞅瞅这类里面到底有没有这方法, 所以把这个jar包下载下来之后拖到idea里一看……………………………………

果然没有那个方法!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

然后一看jar包里面class的修改时间……………….半年以前。

行吧你赢了。

重新编译这个依赖jar包, 更新部署, 问题解决。