Java異常處理設計(三)

接着上一篇講。html

 

一個異常日誌處理的例子:java

 

拋出異常的地方爲:spring

 

try{sql

  ... ...//省略N行apache

}catch( Exception e){tomcat

  throw new RuntimeException ("jar文件加載異常!name="+jarFileName, e);mvc

}app

 

打印異常的地方爲:工具

 

logger.error(e, "類文件加載失敗");測試

 

這是很正常的手法,打印出堆棧信息,並附加上一些額外信息。

 

 

最初,異常堆棧信息是這樣的:

 

(堆棧信息有點多,你們快速往下面看……)

類文件加載失敗
java.lang.RuntimeException: jar文件加載異常!D:\opt\app\WebSphere\output\report\file\loadclass\照片.jar
       at com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:123)
       at com.proj.report.backmanage.addin.control.ClassLoadController.loadClass(ClassLoadController.java:41)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.zollty.framework.mvc.support.HandlerMetaInfo.invokeMethod(HandlerMetaInfo.java:34)
       at org.zollty.framework.mvc.handler.support.ControllerHandler.invoke(ControllerHandler.java:60)
       at org.zollty.framework.mvc.handler.support.HandlerChainImpl.doNext(HandlerChainImpl.java:50)
       at com.proj.report.backmanage.interceptor.AccessRightInterceptor.dispose(AccessRightInterceptor.java:62)
       at sun.reflect.GeneratedMethodAccessor43.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.zollty.framework.mvc.support.HandlerMetaInfo.invokeMethod(HandlerMetaInfo.java:34)
       at org.zollty.framework.mvc.handler.support.InterceptorHandler.invoke(InterceptorHandler.java:58)
       at org.zollty.framework.mvc.handler.support.HandlerChainImpl.doNext(HandlerChainImpl.java:50)
       at com.proj.report.backmanage.interceptor.AdminRightInterceptor.dispose(AdminRightInterceptor.java:56)
       at sun.reflect.GeneratedMethodAccessor42.invoke(Unknown Source)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:597)
       at org.zollty.framework.mvc.support.HandlerMetaInfo.invokeMethod(HandlerMetaInfo.java:34)
       at org.zollty.framework.mvc.handler.support.InterceptorHandler.invoke(InterceptorHandler.java:58)
       at org.zollty.framework.mvc.handler.support.HandlerChainImpl.doNext(HandlerChainImpl.java:50)
       at org.zollty.framework.mvc.servlet.DispatcherController.handleRequest(DispatcherController.java:52)
       at org.zollty.framework.mvc.DispatcherServlet.dispatcher(DispatcherServlet.java:69)
       at org.zollty.framework.mvc.DispatcherServlet.doPost(DispatcherServlet.java:33)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
       at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
       at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
       at java.lang.Thread.run(Thread.java:619)
Caused by: java.util.zip.ZipException: error in opening zip file
       at java.util.zip.ZipFile.open(Native Method)
       at java.util.zip.ZipFile.(ZipFile.java:114)
       at java.util.jar.JarFile.(JarFile.java:133)
       at java.util.jar.JarFile.(JarFile.java:70)
       at com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:120)
       ... 39 more

 

這是一個很簡單的報錯,可是堆棧倒是一大堆,讓人茫然。其實,我想說的是,這個堆棧信息還算少的,在Websphere下,報錯信息還要多,咱們的錯誤日誌文件,一般都是1分鐘幾M甚至幾十M,我下載的日誌文件有800多M的。

 

通過我對不少日誌文件的分析,發現其中90%的報錯信息是冗餘的。

 

通過我對異常的特殊處理,如今錯誤日誌變成了以下形式:

 

16:07:59,415 ERROR ClassLoadController:29 - 類文件加載失敗 |- java.lang.RuntimeException: jar文件加載異常!D:\opt\app\WebSphere\output\report\file\loadclass\照片.jar

       at com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:123)

       at com.proj.report.backmanage.addin.control.ClassLoadController.loadClass(ClassLoadController.java:41)

       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

       ... 6 more

       at com.proj.report.backmanage.interceptor.AccessRightInterceptor.dispose(AccessRightInterceptor.java:62)

       ... 6 more

       at com.proj.report.backmanage.interceptor.AdminRightInterceptor.dispose(AdminRightInterceptor.java:56)

       ... 23 more

Caused by: java.util.zip.ZipException: error in opening zip file

       at java.util.zip.ZipFile.open(Native Method)

       at java.util.zip.ZipFile.(ZipFile.java:114)

       at java.util.jar.JarFile.(JarFile.java:133)

       ... 1 more

       at com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:120)

       ... 39 more

 

 

注意看,上面的錯誤日誌少了不少,某些地方用「... 6 more」「... 23 more」代替了。

這樣精簡以後,對於錯誤的定位就清晰多了。

 

例如,我來分析一下上面的日誌:

1)首先,讀它的錯誤信息:

類文件加載失敗 |- java.lang.RuntimeException: jar文件加載異常!D:\opt\app\WebSphere\output\report\file\loadclass\照片.jar

       我瞭解錯誤的概況「類文件加載失敗了」,進一步緣由是「照片.jar這個jar文件加載異常」

2)再看緊跟着錯誤信息的下面三行錯誤通過的類路徑:

com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:123)

       at com.proj.report.backmanage.addin.control.ClassLoadController.loadClass(ClassLoadController.java:41)

       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

       從這三行數據,我得知,這個異常信息是從ClassLoaderUtils.loadJar(ClassLoaderUtils.java:123)這個地方被new出來的。能夠猜想,這個地方有以下一個語句:throw new RuntimeException()。又根據下面有Caused by: java.util.zip.ZipException語句,因此判定,真正的寫法是throw new RuntimeException(e),其中這個e的類型是java.util.zip.ZipException。

       在這以後的數據,是程序調用的軌跡,大概就是通過Http進入到了攔截器和Servlet,進而到了Action(Controller),我只記錄了一些核心的軌跡信息。通常來講,這些軌跡信息是毫無用處的。你甚至能夠所有去掉。只保留項目包名「com.proj.report.*」開頭的信息便可。

 

       再看Caused by語句,這個纔是錯誤的真正原始出處,能夠看到,是

java.util.zip.ZipException: error in opening zip file

       at java.util.zip.ZipFile.open(Native Method)

也就是說,最底層、最源頭的錯誤,是從ZipFile.open(Native Method)裏面new出來的。錯誤信息是:error in opening zip file

       再接着日後面看,看到了最後,是:

com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:120)

       ... 39 more

       這表明,在咱們本身寫的程序中,錯誤的最源頭是

ClassLoaderUtils.loadJar(ClassLoaderUtils.java:120)

       是從這個工具類的第120行拋出來的。

那麼,完整的錯誤軌跡,錯誤的緣由和錯誤出處,咱們都是很是清楚了。並且,根據上面信息,我還能夠分析出程序調用的軌跡:(通常來講,不必,用處不大)

通過上層程序的層層調用,到達了:

       ClassLoadController.loadClass(xx)

而後調用了:

       ClassLoaderUtils.loadJar(xx)

在這個方法中的以下之處:

       ClassLoaderUtils.loadJar(ClassLoaderUtils.java:120)

即120行,拋出了錯誤信息。

 

       這就是核心的程序運行軌跡,至於loadClass之上的軌跡和loadJar以後的軌跡,是其餘API的運行軌跡,屬於咱們沒法控制的範圍,故打印出來意義不大。固然,我寫的這個異常處理工具,是能夠設定的,例如,若是你想看看SpringAPI的運行軌跡,你能夠在不排除它的包名,好比org.springframework.mvc。

 

這樣還不夠,我還寫了一個更強大的工具:ExceptionWrapper,重寫了Throwable的方法。從底層去改造異常信息。說實話,SUN JDK裏面的那個Throwable設計得並很差,以前我一直在IBM JDK上作測試,沒發現問題,換到SUN JDK就出問題了。詳見我寫的一篇文章介紹:

       http://www.cnblogs.com/zollty/p/3396252.html

像Open JDK 和GUN JDK,都是改進過的。我寫的這個ExceptionWrapper,能夠替代JDK自帶的RuntimeException使用。功能更強大。之後我會專門寫一篇文章來介紹這個工具。

 

用ExceptionWrapper包裝後,最終的錯誤堆棧信息爲:

類文件加載失敗 |- jar文件加載異常!D:\opt\was\file\loadclass\照片.jar

Caused by: java.util.zip.ZipException: error in opening zip file

       at java.util.zip.ZipFile.open(Native Method)

       at java.util.zip.ZipFile.(ZipFile.java:114)

       at java.util.jar.JarFile.(JarFile.java:133)

       ... 1 more

       at com.proj.report.common.util.ClassLoaderUtils.loadJar(ClassLoaderUtils.java:122)

       at com.proj.report.backmanage.addin.control.ClassLoadController.loadClass(ClassLoadController.java:41)

       ... 7 more

       at com.proj.report.backmanage.interceptor.AccessRightInterceptor.dispose(AccessRightInterceptor.java:62)

       ... 7 more

       at com.proj.report.backmanage.interceptor.AdminRightInterceptor.dispose(AdminRightInterceptor.java:56)

       這樣,我滿意了。從上面的堆棧信息中,我能很清晰的看到錯誤的緣由和報錯的地方,以及程序運行的軌跡,幾乎接近完美。

相關文章
相關標籤/搜索