現(xiàn)場(chǎng)描述
在升級(jí)了某組件后,應(yīng)用啟動(dòng)時(shí)拋如下異常尿庐,導(dǎo)致啟動(dòng)失敗:
2017-07-13 15:18:53.388 [C6686525] [] [] ERROR c.y.t.m.a.ServiceAspect - NoSuchMethodError
Method:public com.youzan.api.common.response.PlainResult com.youzan.trade.manage.es.service.impl.SearchServiceImpl.getSearchResult(com.youzan.trade.man
age.api.param.SearchQueryParam)
Arguments:{
}
java.lang.NoSuchMethodError: com.youzan.nsq.client.entity.NSQConfig.setLookupAddresses(Ljava/lang/String;)Lcom/youzan/nsq/client/entity/NSQConfig;
at com.youzan.trade.metrics.NsqReporter.connect(NsqReporter.java:41) ~[trade-metrics-core-1.0-RELEASE.jar:na]
at com.youzan.trade.metrics.NsqReporter.<init>(NsqReporter.java:36) ~[trade-metrics-core-1.0-RELEASE.jar:na]
at com.youzan.trade.metrics.Registry.<init>(Registry.java:54) ~[trade-metrics-core-1.0-RELEASE.jar:na]
過(guò)程分析
工程A
引入了組件甲
呢堰、乙
以及丙
均依賴公司內(nèi)二次開(kāi)發(fā)NSQ-client抄瑟,甲
及乙
為采集應(yīng)用,均調(diào)用了NSQ-Client中NSQCongfig的同名方法暮胧,即上日志中提示NoSuchMethodError的方法:
config = new NSQConfig();
config.setLookupAddresses(lookUpAddress);
排查過(guò)程中锐借,發(fā)現(xiàn)組件甲
依賴的NSQ-Client版本為:2.2.20170424-RELEASE 乙
依賴的NSQ-Client版本為2.3.20170424-RELEASE 粗對(duì)比兩者的函數(shù)簽名,方法名往衷,入?yún)⒍家恢鲁琛0偎翰坏闷浣恪:?組內(nèi)同學(xué)阿奎 debug的時(shí)候發(fā)現(xiàn)席舍,兩個(gè)版本的方法返回值不同布轿,當(dāng)時(shí)恍然大悟。自己在問(wèn)題排查是并沒(méi)有注意到返回值信息,因?yàn)樵趦蓚€(gè)lib中調(diào)用時(shí)均未獲取返回值汰扭,但是實(shí)際在編譯過(guò)程中稠肘,已經(jīng)將返回值信息編譯到class文件中。
NSQ-Client兩個(gè)版本相同類中對(duì)應(yīng)方法簽名分別為:
#2.3.20170424-RELEASE
public NSQConfig setLookupAddresses(final String lookupAddresses)
#2.2.20170424-RELEASE
public void setLookupAddresses(String lookupAddresses)
導(dǎo)致分別依賴兩個(gè)版本NSQ-Client且均調(diào)用此方法的lib無(wú)法共存萝毛。
舉一反三
public class NSQPublisher{
private Client c = new Client();
public void doSome(){
c.command();
}
public static void main(String[] args){
NSQPublisher publisher = new NSQPublisher();
publisher.doSome();
}
}
public class Client{
public void command(){
System.out.println("Do command");
}
}
定義兩個(gè)類项阴,編譯執(zhí)行,正常輸出:
? Desktop javac -cp . Client.java
? Desktop javac -cp . NSQPublisher.java
? Desktop java NSQPublisher
Do command
此時(shí)將Client中的command調(diào)整為返回boolean值笆包,再編譯執(zhí)行环揽,問(wèn)題重現(xiàn):
? Desktop javac -cp . Client.java
? Desktop java NSQPublisher
Exception in thread "main" java.lang.NoSuchMethodError: Client.command()V
at NSQPublisher.doSome(NSQPublisher.java:5)
at NSQPublisher.main(NSQPublisher.java:10)
直接查看反編譯后信息:
? Desktop javap -c NSQPublisher.class
Compiled from "NSQPublisher.java"
public class NSQPublisher {
public NSQPublisher();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #2 // class Client
8: dup
9: invokespecial #3 // Method Client."<init>":()V
12: putfield #4 // Field c:LClient;
15: return
public void doSome();
Code:
0: aload_0
1: getfield #4 // Field c:LClient;
4: invokevirtual #5 // Method Client.command:()V
7: return
public static void main(java.lang.String[]);
Code:
0: new #6 // class NSQPublisher
3: dup
4: invokespecial #7 // Method "<init>":()V
7: astore_1
8: aload_1
9: invokevirtual #8 // Method doSome:()V
12: return
}
昭然若揭。