使用框架代碼經(jīng)常會(huì)發(fā)生反射異常,而且不好定位幔睬。多次遇到過InvocationTargetException和NoSuchMethodError錯(cuò)誤勉痴,恰巧今天同事遇到這個(gè)問題我纪,決定記錄一下。此次遇到這兩個(gè)異常同時(shí)發(fā)生潜支,其實(shí)兩者沒有關(guān)聯(lián)甸赃,只是后面的是根本原因,而前面的是大的包裝異常冗酿。
InvocationTargetException##
先看jdk1.6中的描述:
public class InvocationTargetException extends Exception
“InvocationTargetException is a checked exception that wraps an exception thrown by an invoked method or constructor.”
InvocationTargetException 是一種包裝由調(diào)用方法或構(gòu)造方法所拋出異常的受檢查異常埠对。 從版本 1.4 開始,此異常已經(jīng)更新裁替,符合通用異常鏈機(jī)制项玛。“目標(biāo)異橙跖校”是在構(gòu)造的時(shí)候提供的襟沮,可以通過 getTargetException() 方法訪問,這類對(duì)象目前被認(rèn)為是導(dǎo)致異常的原因昌腰,可以通過 Throwable.getCause() 方法訪問它开伏。
通常發(fā)生在采用反射的方式調(diào)用方法的時(shí)候,比如顯式的反射或使用框架剥哑。此異常會(huì)吞掉其他所有異常硅则,要想看到進(jìn)一步具體原因,就需要查看打出來的異常下面的“Caused By:”或使用getCause()獲取株婴。
NoSuchMethodError##
同樣先看下jdk1.6中的描述:
public class NoSuchMethodError extends IncompatibleClassChangeError
當(dāng)應(yīng)用程序試圖調(diào)用類(靜態(tài)或?qū)嵗┑闹付ǚ椒ㄔ醭妫擃愐巡辉倬哂性摲椒ǖ亩x時(shí),拋出該異常困介。通常由編譯器捕獲該錯(cuò)誤大审;僅當(dāng)類定義發(fā)生不相容的更改時(shí),在運(yùn)行時(shí)才會(huì)發(fā)生該錯(cuò)誤座哩。編譯器捕獲很容易解決徒扶,其實(shí)我們通常遇到的是運(yùn)行時(shí)錯(cuò)誤。比如根穷,使用泛型編程(框架代碼里通常有大量泛型)時(shí)方法參數(shù)會(huì)被編譯器擦除姜骡,而反射調(diào)用時(shí)使用了具體類型導(dǎo)致方法簽名不匹配导坟。
**通常發(fā)生此錯(cuò)誤的原因大概有(也是定位問題的優(yōu)先步驟): **
- 自己顯示使用反射或使用框架調(diào)用一個(gè)類的確不包含的方法。但反射使用時(shí)編譯器不會(huì)報(bào)錯(cuò)圈澈。
- 被調(diào)用的方法的確存在惫周。此時(shí)有可能是:
2.1 應(yīng)用環(huán)境中存在同全路徑名的類,但類里方法不同康栈,一個(gè)有此方法一個(gè)沒有此方法递递,但jvm調(diào)用了沒有此方法的類∩睹矗或應(yīng)用環(huán)境中包含了同一個(gè)框架的不同版本的jar包登舞,有方法不兼容,比如spring,hibernate的包都可能悬荣。
解決辦法:如果是框架類報(bào)錯(cuò)菠秒,一般刪除沖突的低版本框架包;如果是自己的類隅熙,則查看是否可以重命名類稽煤。
2.2 不存在同名的類,而且報(bào)錯(cuò)的類是自己的類而不是框架的類囚戚,可能是自己修改了自己的類簽名(比如參數(shù)類型)酵熙,環(huán)境里沒有更換最新的class。
解決辦法:clean工程再重新打包驰坊。
本人遇到異常信息##
java.lang.reflect.InvocationTargetException
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
com.opensymphony.xwork2.DefaultActionInvocation.invokeActio
java.lang.NoSuchMethodError: com.**.framework.appsp.service.UsersService.saveOrUpdate(Lcom/**/framework/appsp/bean/UsersEntity;)Ljava/lang/String;
com.**.framework.appsp.action.UsersAction.addUser(UsersAction.java:73)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
看到InvocationTargetException后直接找下面的Caused By:(如果沒有詳細(xì)異常就自己再修改下代碼用getCause()捕獲一下)
java.lang.NoSuchMethodError:
com.**.framework.appsp.service.UsersService.saveOrUpdate(Lcom/**/framework/appsp/bean/UsersEntity;)Ljava/lang/String;
(備注:這里是提示的方法簽名匾二,方法名稱(方法參數(shù))返回值,通過這里也可以看下jvm實(shí)際調(diào)用的方法是否為自己想調(diào)用的方法)
根據(jù)提示saveOrUpdate找不到拳芙,但實(shí)際是存在的察藐,而且這個(gè)是自己實(shí)現(xiàn)的類。在系統(tǒng)環(huán)境中沒有找到?jīng)_突的同名類舟扎,應(yīng)該是編譯過程有問題分飞。重新clean 打包专甩,刪除瀏覽器緩存遵堵,tomcat緩存,啟動(dòng)值桩,一切正常了羡疗。這里說的挺輕松染服,其實(shí)定位過程很糾結(jié)。
InvocationTargetException異常的原因各種各樣叨恨,還是具體問題具體看待柳刮,一定要找到這個(gè)異常后面的真正異常再去分析。
NoSuchMethodException和NoSuchMethodError##
NoSuchMethodException繼承自Exception;
NoSuchMethodError繼承自Error秉颗,一般有兼容性問題時(shí)會(huì)拋出該異常痢毒;
前者是普通的A.b()形式調(diào)用,在極其特殊的情況下站宗,發(fā)現(xiàn)A類里面沒有b方法時(shí)拋出闸准,一般情況下這種錯(cuò)誤是不會(huì)存在的,連編譯前的檢查都沒法通過梢灭。但是可能在某些極端情況下出現(xiàn),比如字節(jié)碼在內(nèi)存中被改了蒸其。
后者我估計(jì)是在反射的時(shí)候敏释,依據(jù)傳入的方法名尋找方法時(shí)沒找到。Error代表的是無法恢復(fù)的錯(cuò)誤摸袁,必須由jvm處理或者終止钥顽,而Exception是可以恢復(fù)的異常,程序員可以自行捕獲靠汁。
NoSuchMethodError:當(dāng)應(yīng)用程序試圖調(diào)用類(靜態(tài)或?qū)嵗┑闹付ǚ椒ǚ浯螅擃愐巡辉倬哂性摲椒ǖ亩x時(shí),拋出該異常蝶怔。通常由編譯器捕獲該錯(cuò)誤奶浦;僅當(dāng)類定義發(fā)生不相容的更改時(shí),在運(yùn)行時(shí)才會(huì)發(fā)生該錯(cuò)誤踢星。
NoSuchMethodException:無法找到某一特定方法時(shí)澳叉,拋出該異常。