自定義Springboot全局異常類


一、簡要說明

如何實現網上文章基本是隨便一搜就可以很快找到, 這里不再贅述.

二、Spring-web和Spring-webmvc

通過idea查看到兩個注解位於 spring-web-5.2.2.RELEASE.jar包內,.

而這里maven依賴有spring web 和spring webmvc 兩個包;

查詢到spring web主要提供了HTTP的功能集成,

而spring-webmvc基於spring-web, 從而提供servlet功能. (參考: Maven dependency spring-web vs spring-webmvc)

2.2.5 Web
The Web layer consists of the spring-web, spring-webmvc, spring-websocket, and spring-webmvc-portlet modules.

The spring-web module provides basic web-oriented integration features such as multipart file upload functionality and the initialization of the IoC container using Servlet listeners and a web-oriented application context. It also
contains an HTTP client and the web-related parts of Spring’s remoting support.

The spring-webmvc module (also known as the Web-Servlet module) contains Spring’s model-view-controller (MVC) and REST Web Services implementation for web applications. Spring’s MVC framework provides a clean > separation between domain model code and web forms and integrates with all of the other features of the Spring Framework.

The spring-webmvc-portlet module (also known as the Web-Portlet module) provides the MVC implementation to be used in a Portlet environment and mirrors the functionality of the Servlet-based spring-webmvc module.

三、兩個注解

我們已經知道主要使用@ControllerAdvice@ExceptionHandler這兩個注解來實現全局異常類的定義.

  • @ControllerAdvice
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] assignableTypes() default {};

    Class<? extends Annotation>[] annotations() default {};
}
  • @ExceptionHandler
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExceptionHandler {
    Class<? extends Throwable>[] value() default {};
}

通過在spring framework - web mvc官方文檔中搜索@ControllerAdvice 得到了一些信息:

(以下部分摘自Spring文檔)

  • Resolves exceptions by invoking an @ExceptionHandler method in a @Controller or a @ControllerAdvice class. See @ExceptionHandler methods.

1.3.6. Exceptions (@ExceptionHandler methods)

文檔中說"@Controller和@ControllerAdvice類可以具有 @ExceptionHandler處理控制器方法異常的方法", 但是經過嘗試發現@Controller和@ExceptionHandler組合並沒有實現.

  • 兩種匹配異常的方式

  • 直接匹配

該異常可能與正在傳播的頂級異常(即,直接IOException引發的異常)匹配,也可能與頂級包裝器異常(例如,IOException包裝在中IllegalStateException)的直接原因匹配 。
對於匹配的異常類型,如前面的示例所示,最好將目標異常聲明為方法參數。當多個異常方法匹配時,根源異常匹配通常比原因異常匹配更可取。更具體地,ExceptionDepthComparator用於根據異常從引發的異常類型的深度對異常進行排序。

    @ExceptionHandler
    public ResponseEntity<String> handle(IOException ex) {
        // ...
    }
  • 注釋聲明可以縮小異常類型以使其匹配,如以下示例所示:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(IOException ex) {
    // ...
}
  • 您甚至可以使用帶有非常通用的參數簽名的特定異常類型的列表,如以下示例所示:
@ExceptionHandler({FileSystemException.class, RemoteException.class})
public ResponseEntity<String> handle(Exception ex) {
    // ...
}
  • 根和原因異常匹配之間的區別可能令人驚訝。

在IOException前面顯示的變體中,通常以實際FileSystemException或RemoteException實例作為參數來調用該方法,因為這兩個方法都從擴展IOException。但是,如果任何此類匹配異常都在本身為的包裝器異常中傳播IOException,則傳入的異常實例就是該包裝器異常。

在handle(Exception)變體中,行為甚至更簡單。在包裝方案中,總是使用包裝程序異常來調用此方法,ex.getCause()在這種情況下,將找到實際匹配的異常。僅當將它們作為頂級異常拋出時,傳入的異常才是實際的FileSystemException或 RemoteException實例。

我們通常建議您在參數簽名中盡可能具體,以減少根類型和原因異常類型之間不匹配的可能性。考慮將多重匹配方法分解為單個@ExceptionHandler 方法,每個方法都通過其簽名匹配單個特定的異常類型。

在多種@ControllerAdvice安排中,我們建議聲明@ControllerAdvice優先級並以相應順序聲明您的主根異常映射。盡管根異常匹配優先於原因,但這是在給定控制器或@ControllerAdvice類的方法之間定義的。這意味着優先級較高的@ControllerAdvicebean 上的原因匹配優於優先級 較低的@ControllerAdvicebean 上的任何匹配(例如,根) 。

  • 最后但並非最不重要的一點是,@ExceptionHandler方法實現可以選擇通過以原始形式重新拋出異常來退出處理給定異常實例。在僅對根級別匹配或無法靜態確定的特定上下文中的匹配感興趣的情況下,這很有用。重新拋出的異常會在其余的解決方案鏈中傳播,就像給定的@ExceptionHandler方法最初不會匹配一樣。

@ExceptionHandlerSpring MVC中對方法的支持建立在HandlerExceptionResolver機制DispatcherServlet 級別上。

  • @ExceptionHandler 支持的方法參數:(見原文)
  • @ExceptionHandler 方法支持的返回值:(見原文)

REST API exceptions

REST服務的常見要求是在響應正文中包含錯誤詳細信息。Spring框架不會自動執行此操作,因為響應主體中錯誤詳細信息的表示是特定於應用程序的。但是,a @RestController可以使用@ExceptionHandler帶有ResponseEntity返回值的方法來設置響應的狀態和主體。也可以在@ControllerAdvice類中聲明此類方法以將其全局應用。

在響應主體中實現具有錯誤詳細信息的全局異常處理的應用程序應考慮extend ResponseEntityExceptionHandler,它提供對Spring MVC引發的異常的處理,並提供用於自定義響應主體的鈎子。要使用此功能,請創建一個的子類 ResponseEntityExceptionHandler,用對其進行注釋@ControllerAdvice,覆蓋必要的方法,然后將其聲明為Spring bean。

1.3.7. Controller Advice

通常@ExceptionHandler,,@InitBinder和@ModelAttribute方法適用於@Controller聲明它們的類(或類層次結構)。如果要使此類方法更全局地應用(跨控制器),則可以在帶有@ControllerAdvice或注釋的類中聲明它們@RestControllerAdvice。

@ControllerAdvice帶有注釋@Component,這意味着可以通過組件掃描將此類注冊為Spring Bean 。@RestControllerAdvice是用@ControllerAdvice和注釋的組合注釋@ResponseBody,從本質上講,這意味着 @ExceptionHandler方法是通過消息轉換(與視圖解析或模板渲染相比)呈現給響應主體的。

在啟動時,用於@RequestMapping和@ExceptionHandler 方法的基礎結構類會檢測帶有注釋的Spring bean @ControllerAdvice,然后在運行時應用其方法。全局@ExceptionHandler方法(來自@ControllerAdvice)適用於局部方法(來自@Controller)。相比之下,全局@ModelAttribute 和@InitBinder方法先於局部方法。

默認情況下,@ControllerAdvice方法適用於每個請求(即所有控制器),但是您可以通過使用批注上的屬性將其范圍縮小到控制器的子集,如以下示例所示:

// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}

前面示例中的選擇器在運行時進行評估,如果廣泛使用,可能會對性能產生負面影響。有關@ControllerAdvice 更多詳細信息,請參見 javadoc。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM