增量发布的NoSuchMethodError 异常

阅读更多
NoSuchMethodError多是因为类冲突,没有加载版本需要的class而加载了其他路径下的class,但是本文记录的是重载代码修改在增量发布环境下出现的异常情况!
调用者:
package util;
 
public class Invoker {
public static void main(String[] args) {
CommUtil c=new CommUtil();
String s="ssssssssss";
System.out.println(c.format(s));
}
}
 
报异常:
Exception in thread "main" java.lang.NoSuchMethodError: util.CommUtil.format(L
va/lang/String;)Ljava/lang/String;
at util.Invoker.main(Invoker.java:9)
 
 
原因是因为重载方法删除后,调用者的的代码没有重新编译。该问题出现在“ 增量发布”的场景,只发布了代码修改过的CommUtil.class,没有发布Invoker的class
 
 
当CommUtil.java 中有如下两个重载方法时
package util;
 
public class CommUtil {
 
public String format(String v ){
 
return "String format "+v;
}
 
public String format(Object v){
return "Object format "+v.toString();
}
 
}
 
调用类编译后class的反编译后如下:
 
D:\clstest\util>javap -c Invoker.class
Compiled from "Invoker.java"
public class util.Invoker {
public util.Invoker();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."":
()V
4: return
 
public static void main(java.lang.String[]);
Code:
0: new #16 // class util/CommUtil
3: dup
4: invokespecial #18 // Method util/CommUtil."":()V
 
7: astore_1
8: ldc #19 // String ssssssssss
10: astore_2
11: getstatic #21 // Field java/lang/System.out:Ljava/
io/PrintStream;
14: aload_1
15: aload_2
16: invokevirtual #27 // Method util/CommUtil.format:( Ljav
a/lang/String;)Ljava/lang/String;
19: invokevirtual #31 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
22: return
}
 
当删除format(String v) 这个方法后,CommUtill.java内容如下:
 
package util;
public class CommUtil {
 
public String format(Object v){
return "Object format "+v.toString();
}
 
}
 
javap -c 反编译如下:
D:\src\ssm3\target\test-classes\util>javap -c Invoker.class
Compiled from "Invoker.java"
public class util.Invoker {
public util.Invoker();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."":
()V
4: return
 
public static void main(java.lang.String[]);
Code:
0: new #16 // class util/CommUtil
3: dup
4: invokespecial #18 // Method util/CommUtil."":()V
 
7: astore_1
8: ldc #19 // String ssssssssss
10: astore_2
11: getstatic #21 // Field java/lang/System.out:Ljava/
io/PrintStream;
14: aload_1
15: aload_2
16: invokevirtual #27 // Method util/CommUtil.format: (Ljav
a/lang/Object;)Ljava/lang/String;
19: invokevirtual #31 // Method java/io/PrintStream.printl
n:(Ljava/lang/String;)V
22: return
}
 
 
总结:
 
重载是编译是的多态行为,java编译器会根据多态的方法的参数就近选择一个方法编译。如上面例子,当CommUtil 有format(String v )方法时候,Invoker 调用format时会被编译成
 16: invokevirtual #27 // Method util/CommUtil.format:( Ljav
a/lang/String;)Ljava/lang/String;
 
但是当删除format(String v )只留下format(Object v )时,会被编译成
 16: invokevirtual #27 // Method util/CommUtil.format: (Ljav
a/lang/Object;)Ljava/lang/String;
 
所以在生成环境的增量发布流程需要优化,需要注意重载代码修改后的相关优化或者谨慎对重载方法进行修改

你可能感兴趣的:(增量发布)