樓主前幾天寫(xiě)了一篇“Java子線程中的異常處理(通用)”文章,介紹了在多線程環(huán)境下3種通用的異常處理方法。
但是平時(shí)大家的工作一般是基于開(kāi)發(fā)框架進(jìn)行的(比如Spring MVC,或Spring Boot),所以會(huì)有相應(yīng)特定的異常處理方法,這篇文章要介紹的就是web應(yīng)用中的異常處理。
想快速解決問(wèn)題的小伙伴可以只看“解決辦法”,想進(jìn)一步了解細(xì)節(jié)的小伙伴還可以看“深入剖析”部分。
適用場(chǎng)景
使用Spring MVC或Spring Boot框架搭建的web應(yīng)用
解決辦法
@ControllerAdvice注解 + @ExceptionHandler注解
實(shí)現(xiàn)一個(gè)異常處理類(lèi),在類(lèi)上應(yīng)用@ControllerAdvice注解,并在異常處理方法上應(yīng)用@ExceptionHandler注解。那么在web應(yīng)用中,當(dāng)Controller的@RequestMapping方法拋出指定的異常類(lèi)型時(shí),@ExceptionHandler修飾的異常處理方法就會(huì)執(zhí)行。
示例:
@ControllerAdvicepublic class WebServerExceptionHandler { Logger log = LoggerFactory.getLogger(this.getClass()); public WebServerExceptionHandler() { } // 指定捕獲的異常類(lèi)型,這里是自定義的SomeException @ExceptionHandler({SomeException.class}) public ResponseEntity handle(HttpServletResponse response, SomeException ex) { WebServerExceptionResponse body = new WebServerExceptionResponse(); body.setStatus(ex.getStatus()); body.setMessage(ex.getMessage()); this.log.info(“handle SomeException, status:{}, message:{}”, new Object[]{body.getStatus(), body.getMessage()}); return new ResponseEntity(body, HttpStatus.valueOf(ex.getStatus())); } // 指定捕獲的異常類(lèi)型,這里是自定義的OtherException @ExceptionHandler({OtherException.class}) public ResponseEntity handle(HttpServletResponse response, OtherException ex) { WebServerExceptionResponse body = new WebServerExceptionResponse(); body.setStatus(ex.getStatus()); body.setMessage(ex.getMessage()); this.log.info(“handle OtherException, status:{}, message:{}”, new Object[]{body.getStatus(), body.getMessage()}); return new ResponseEntity(body, HttpStatus.valueOf(ex.getStatus())); }}
深入剖析
@ControllerAdvice的定義如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface ControllerAdvice { String[] value() default {}; String[] basePackages() default {}; Class[] basePackageClasses() default {}; Class[] assignableTypes() default {}; Class[] annotations() default {};}
可以看出它應(yīng)用在TYPE類(lèi)型的元素上(也即class或interface),運(yùn)行時(shí)生效。
作用是Controller類(lèi)的幫助注解,一般搭配@ExceptionHandler注解,用來(lái)處理Controller的@RequestMapping修飾的方法拋出的異常。
樓主根據(jù)源碼的注釋整理了5個(gè)參數(shù)的含義,它們都是用來(lái)限定需要處理的Controller的:
- value():等同于basePackages,表示需要被處理的Controller包名數(shù)組,例如 @ControllerAdvice(“org.my.pkg”)。如果不指定,就代表處理所有的Controller類(lèi)
- basePackages():表示需要被處理的Controller包名數(shù)組,例如 @ControllerAdvice(basePackages={“org.my.pkg”,”org.my.other.pkg”})
- basePackageClasses():通過(guò)標(biāo)記類(lèi)來(lái)指定Controller包名數(shù)組
- assignableTypes():通過(guò)類(lèi)的Class對(duì)象來(lái)指定Controller包名數(shù)組
- annotations():被注解修飾的Controller需要被處理
性能考慮:不要指定過(guò)多的參數(shù)和異常處理策略,因?yàn)楫惓z查和處理都是在運(yùn)行時(shí)做的。
@ExceptionHandler的定義如下:
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ExceptionHandler { /** * Exceptions handled by the annotated method. If empty, will default to any * exceptions listed in the method argument list. */ Class[] value() default {};}
可以看出它作用在方法上面,而且參數(shù)很好理解,就是需要處理的異常類(lèi)的Class對(duì)象數(shù)組。
但是,它對(duì)修飾的異常處理方法的參數(shù)和返回值有限定,樓主根據(jù)源碼的注釋整理如下:
(1)異常處理方法的參數(shù)限定,可以是以下類(lèi)型,順序任意:
- 異常類(lèi)對(duì)象
- HttpServletRequest、HttpServletResponse
- HttpSession
- InputStream/Reader、OutputStream/Writer
(2)異常處理方法的返回值限定,最終會(huì)寫(xiě)入response流:
- ResponseEntity
- HttpServletResponse
- ModelAndView
- Model
- Map
- View
總結(jié)
以上就是在Spring web應(yīng)用中的異常處理方法:使用@ControllerAdvice搭配@ExceptionHandler修飾自定義異常處理方法,處理來(lái)自Controller類(lèi)中的@RequestMapping方法拋出的異常。
使用時(shí)需要根據(jù)實(shí)際情況,合理設(shè)置@ControllerAdvice和@ExceptionHandler的參數(shù)。