Spring-异常处理(9种讲解)

03-07 阅读 0评论

目录

Spring-异常处理(9种讲解),Spring-异常处理(9种讲解),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,管理,第1张
(图片来源网络,侵删)

前言

Spring Boot默认的异常处理机制

@ResponseStatus设置 HTTP 状态代码

@ResponseStatus 编程替代方案-ResponseStatusException

控制器级@ExceptionHandler

HandlerExceptionResolver接口

Spring-异常处理(9种讲解),Spring-异常处理(9种讲解),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,管理,第2张
(图片来源网络,侵删)

使用注解实现异常分类管理(@ControllerAdvice 和 @ExceptionHandler)

使用 @ControllerAdvice 对不同的 Controller 分别捕获异常并处理

ResponseStatusException(Spring 5及以上版本)

Spring Web MVC 中的异常处理流程


前言

  • Spring 为我们提供了处理异常的工具,而不仅仅是简单的“try-catch”块
  • 为了使用这些工具,我们应用了一些注解,使我们能够将异常处理视为横切关注点
  • 比如:
  • @ResponseStatus
  • @ExceptionHandler
  • @ControllerAdvice

    Spring Boot默认的异常处理机制

    • 假设我们有一个名为 ProductController 的控制器,当具有给定 id 的 Product 不存在时,其 getProduct(...) 方法会抛出 NoSuchElementFoundException 运行时异常
    • 如下:
    • Spring-异常处理(9种讲解)
    • 如果我们使用无效的 id 调用 /product API,服务将抛出 NoSuchElementFoundException 运行时异常,我们将得到以下响应:
    • Spring-异常处理(9种讲解)
    • 我们可以看到,除了格式良好的错误响应之外,有效负载没有给我们任何有用的信息
    • 甚至 message 字段也是空的,我们可能希望包含“未找到 id 1 的项目”之类的内容
    • 让我们从修复错误消息问题开始
    • Spring Boot 提供了一些属性,我们可以使用它们添加异常消息、异常类,甚至堆栈跟踪作为响应负载的一部分:
    • Spring-异常处理(9种讲解)
    • 在 application.yml 中使用这些 Spring Boot 服务器属性,我们可以在某种程度上改变错误响应
    • 现在,如果我们使用无效的 id 再次调用 /product API,我们将得到以下响应:
    • Spring-异常处理(9种讲解)
    • 请注意,我们已将属性 include-stacktrace 设置为 on_trace_param ,这意味着仅当我们在 URL 中包含 trace 参数时( ?trace=true ),我们将在响应负载中获得堆栈跟踪:
    • Spring-异常处理(9种讲解)
    • 我们尽可能希望将 include-stacktrace 标志的值保存为 never ,至少在生产中,因为它可能会揭示我们应用程序的内部工作原理
    • 状态和错误消息 - 500 - 表明我们的服务器代码有问题,但实际上这是客户端错误,因为客户端提供了无效的 ID
    • 我们当前的状态代码没有正确反映这一点
    • 但这就是我们可以使用 server.error 配置属性的范围,因此我们必须查看 Spring 提供的注解

      @ResponseStatus设置 HTTP 状态代码

      概述:

      • 在 Spring MVC 中,我们有很多方法来设置 HTTP 响应的状态码
      • 其中最直接的方法:使用 @ResponseStatus 注解
      • 它将一个方法或异常类标注一个应返回的HTTP状态码(code())和原因说明(reason())(即将特定的HTTP状态码和原因与一个控制器方法或异常类相关联)

        用途:

        Spring-异常处理(9种讲解),Spring-异常处理(9种讲解),词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,使用,我们,管理,第8张
        (图片来源网络,侵删)
        • 在方法上使用:当你想要显式声明一个Spring MVC控制器方法完成后应该返回的HTTP状态码时,可以在该方法上使用@ResponseStatus;例如,可以将201 CREATED状态码关联到创建资源的操作上
        • 在异常上使用:你可以创建一种异常,当该异常被抛出时,自动返回指定的HTTP状态码;在异常类上使用@ResponseStatus可以直接将异常映射到HTTP状态响应中

          参数:

          • value/code:用于指定HTTP状态码
          • reason:可选参数,用于提供状态码的原因描述;这个描述将被发送到客户端
          • Spring-异常处理(9种讲解)

            注意事项:

            • 当处理器方法被调用时,该状态码将被加入到HTTP响应中,但是不会覆盖其他方式所设置的状态信息,例如通过ResponseEntity或"Redirect"设置的信息,因为 ResponseEntity 对象包含了完整的响应信息,会优先使用
            • 警告:在异常类上使用这个注解,或当设置这个注解的reason属性时,将会使用HttpServletResponse.sendError方法
            • 在HttpServletResponse.sendError被使用后,响应被视为已完成,不应该再进行进一步的写入
            • 另外,Servlet容器通常会创建一个HTML错误页面,因此使用reason对于REST API而言是不合适的,因为REST调用通常预期接收JSON或XML格式的响应体
            • 对于这种情况,最好是使用ResponseEntity作为返回类型,并避免使用@ResponseStatus注解
            • 注意:一个控制器类也可以被标注为@ResponseStatus,这样它就会被该类以及其子类中所有使用@RequestMapping和@ExceptionHandler的方法继承,除非这些方法通过本地@ResponseStatus声明进行了覆盖

              自定义异常类:

              • 在Spring Boot中,可以通过在自定义的异常类上使用@ResponseStatus注解来设置HTTP状态
              • 当这个异常被抛出时,就会返回设置的状态对应的响应
              • 需要注意的是,必须继承非检查异常(RuntimeException及其子类)
              • Spring-异常处理(9种讲解)
              • Spring-异常处理(9种讲解)
              • Spring-异常处理(9种讲解)
              • Spring-异常处理(9种讲解)

                底层原理:

                • 注解底层还是通过设置 response.setStatus 来实现
                • 在@RequestMapping方法执行完成,Spring解析返回值之前,进行了responseStatus设置
                • 代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus
                • this对象指当前的ServletInvocableHandlerMethod,看到@ResponseStatus的reason不为空,就调用response.sendError;reason为空,就调用setStatus方法仅仅设置响应状态码
                • Spring-异常处理(9种讲解)
                • 代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
                • 发现如果ServletInvocableHandlerMethod的responseReason有值,也就是@ResponseStatus有reason属性,@RequestMapping方法返回值都不处理了,直接返回
                • Spring-异常处理(9种讲解)
                • 也就是说只要有@ResponseStatus的reason属性标注在处理器Controller类或者方法上,比如响应状态码code设置为404,reason设置为页面没找到,那 tomcat 展示界面是大概这样,展示信息就是我们写的reason属性
                • Spring-异常处理(9种讲解)
                • @ResponseStatus(code=A,reason=B)标注在@RequestMapping方法上,作用效果与response.sendError(A,B)是一样的

                  @ResponseStatus 编程替代方案-ResponseStatusException

                  概述:

                  • 从 Spring 5.0 开始引入
                  • 特别适用于 Spring WebFlux,也可以在 Spring MVC 中使用
                  • 使用 ResponseStatusException 可以在代码中的任何地方抛出特定的 HTTP 状态码(比如 404 NOT FOUND 或 400 BAD REQUEST)以及一个可选的错误消息
                  • 这个类继承自 RuntimeException,因而它是一个不受检异常(unchecked exception),你不需要在方法签名上声明它,也不必强制捕获它
                  • 其主要的目的是通过编程方式控制异常以及相应的 HTTP 状态码和错误信息的返回
                  • ResponseStatusException 类的主构造函数如下:
                  • Spring-异常处理(9种讲解)
                    • status:一个 HttpStatus 枚举值,表示要返回的 HTTP 状态码
                    • reason:一个表示错误详情的 String;这个消息可能会返回给客户端,所以在设置时要注意安全性和敏感信息泄露的问题
                    • cause:引发异常的原始 Throwable 对象;这不会直接发送给客户端,通常用于日志记录目的
                    • 有几种构造函数版本,不一定全部需要传入(reason)或(cause),您可以根据实际需求使用它们

                      综合实例:

                      • 下面是一个简单的例子,展示如何在控制器方法中使用 ResponseStatusException:
                      • Spring-异常处理(9种讲解)
                      • 在这个例子中,当找不到给定 ID 的 item 时,会抛出 ResponseStatusException,并且返回状态码 404 NOT FOUND 以及错误信息 “Item not found”

                      • 由于 ResponseStatusException 是RuntimeException的子类,Spring 框架会捕捉到这个异常,并将其转换成相应的 HTTP 响应返回给客户端

                      • 这个机制允许开发者以非常灵活的方式处理各种各样的异常情况

                        继承 ResponseStatusException-自定义异常类

                        • 在 Spring Boot 应用程序中,ResponseStatusException 是一个构建好的异常类,它可以被直接使用来返回特定的 HTTP 状态代码和消息
                        • 你可以在方法中直接抛出它,Spring 框架将负责将异常转化为对应的 HTTP 响应
                        • 但是如果你有特定的需求,比如希望在你的应用程序中创建一系列具有固定状态码和自定义处理逻辑的异常,你可以继承 ResponseStatusException
                        • 下面是一个简单的例子,定义了一个继承自 ResponseStatusException 的自定义异常类:
                        • Spring-异常处理(9种讲解)
                        • 在你的 Spring Boot 应用中使用自定义异常:
                        • Spring-异常处理(9种讲解)
                        • 当 CustomBadRequestException 被抛出时,Spring 框架会捕捉到这个异常,并且根据异常内的信息返回一个 HttpStatus.BAD_REQUEST (400 错误码) 的 HTTP 响应给客户端,并带有 “这里是错误信息” 作为响应体中的错误描述
                        • 通过这种方式,你可以定义不同的自定义异常类型,来处理你应用程序中不同的错误情况,并返回合适的 HTTP 响应

                          继承 ResponseStatusException-自定义响应头信息

                          • 在继承自 ResponseStatusException 的自定义异常类中重写 getResponseHeaders() 方法可以让你添加或者定制返回给客户端的 HTTP 响应头
                          • 默认情况下,ResponseStatusException 没有响应头或者只有基本的响应头
                          • 通过重写这个方法,你可以根据你的业务逻辑需要,添加一些特殊的响应头信息
                          • 例如,你可能想添加一个关于错误的链接,一个特殊的错误追踪 ID,或者控制缓存的头信息
                          • 下面是一个例子,演示了如何在自定义异常中重写 getResponseHeaders() 方法来添加一个自定义的响应头:
                          • Spring-异常处理(9种讲解)
                          • 在控制器中抛出这个自定义的 CustomBadRequestException 将会导致 Spring 框架处理这个异常,并在最终的 HTTP 响应中包含 ‘X-Custom-Error’ 这个头信息
                          • 使用自定义的响应头可以提供更多的上下文信息给调用者,或者用来传达非标准的、特定于应用的消息
                          • 这是一个扩展标准异常处理行为并高度定制异常返回信息的强大方式
                          • 要注意的是,你应该谨慎添加响应头,确保它们不会暴露敏感信息或者与你的 API 设计冲突

                            继承 ResponseStatusException-定制更多异常处理逻辑

                            • 在继承 ResponseStatusException 的自定义异常类中,除了getResponseHeaders()之外,你可能会考虑重写几个其他重要的方法来进一步定制你的异常处理逻辑:
                              1. getMessage():

                                重写这个方法可以让你改变异常的错误消息

                                这个消息通常会被用在日志中,也可能在一些情况下返回给客户端,取决于你的错误处理配置

                              2. getStatus():

                                如果你想根据异常发生的上下文动态改变 HTTP 状态码,可以重写 getStatus() 方法

                              3. getCause():

                                如果你的自定义异常包装了另一个异常,你可以通过 getCause() 方法提供原始的异常;这对于调试和错误跟踪是非常有用的

                              4. printStackTrace() 和 getStackTrace():

                                这些方法可以被用来获取和打印异常的堆栈追踪

                              • 通常这些方法的默认实现足够用了,但如果需要的话,你可以提供更多的信息或者定制格式
                              • 在实际业务情况中,我们可以重写异常类的这些方法来增强错误处理的能力,例如记录额外的调试信息、创建更为详细的错误消息等
                              • 让我们来创建一个更切实的业务场景来展示这一点:
                              • 假设我们有一个在线电商平台,当用户尝试创建订单时,如果库存不足,我们希望抛出一个自定义的异常
                              • 在这个自定义异常中,我们可以重写 getMessage() 方法来提供更丰富的信息,并重写 printStackTrace() 和 getStackTrace() 方法来添加关于库存不足的特定上下文信息
                              • Spring-异常处理(9种讲解)

                                在这个示例中:

                                • getMessage() 被重写以返回一个更为详细的错误信息
                                • printStackTrace() 被重写以打印特定的业务相关错误信息
                                • getStackTrace() 被重写以添加自定义的堆栈跟踪元素,这可能对调试有帮助,显示出是在检查库存时出现了问题
                                • getStatus() 被重写以返回一个特定的HTTP状态;请注意,通常这也可以通过在抛出异常时传递不同的 HttpStatus 枚举值给构造函数来实现
                                • getMessage() 被修改以增加更多的业务信息,如最后库存同步时间
                                • 通过这样重写这些方法,我们可以提供更加具体的错误状态和信息,以便在记录日志、返回给客户端、调试等方面提供有用的上下文

                                  继承 ResponseStatusException-根据异常发生的上下文动态改变 HTTP 状态码

                                  • 根据库存不足时的不同情况来设置不同的状态码(比如,如果只是暂时性的库存问题使用 503 Service Unavailable,如果是产品完全下架则使用 410 Gone)
                                  • 可以在自定义异常类中添加逻辑如下:
                                  • Spring-异常处理(9种讲解)
                                  • 在这个示例中,chooseHttpStatus 方法基于 productDiscontinued 布尔变量的值来选择不同的HTTP状态码
                                  • 如果产品已经停产,那么使用 410 Gone 状态码;如果仅仅是暂时的库存问题,则使用 503 Service Unavailable
                                  • 如此,异常类的构造函数中传入的参数 productDiscontinued 决定了异常应该携带的HTTP状态码

                                    控制器级@ExceptionHandler

                                    • 第一个解决方案是在@Controller级别工作
                                    • 我们将定义一个方法来处理异常并使用@ExceptionHandler进行注解:

                                      Spring-异常处理(9种讲解)

                                      • 这种方法有一个主要缺点:@ExceptionHandler注解的方法仅对特定的 Controller 有效,而不是对整个应用程序全局有效,将其添加到每个控制器使其进行处理异常,不太适合通用异常处理机制
                                      • 我们可以通过让所有控制器扩展基本控制器类来解决此限制
                                      • 然而此解决方案可能是一个问题
                                      • 例如,控制器可能已经从另一个基类扩展,该基类可能位于另一个 jar 中或不可直接修改,或者本身可能不可直接修改
                                      • 接下来,我们将研究另一种解决异常处理问题的方法 - 一种全局的方法

                                        HandlerExceptionResolver接口

                                        • 在SpringMVC中,提供了一个全局异常处理器,用于对系统中出现的异常进行统一处理
                                        • 在一般的系统中,DAO层、Service层及Controller层出现异常都以“throws Exception”的形式向上层抛出,最后都会由SpringMVC的前端控制器(DispatcherServlet)统一交给全局异常处理器进行异常处理
                                        • 在SpringMVC中提供的HandlerExceptionResolver接口可以实现全局异常处理器
                                        • Spring MVC接口HandlerExceptionResolver用于抽象一个异常解析器
                                        • 这种异常解析器被用于分析请求处理器Handler映射或者执行过程中的异常,将这些异常转换成其他形式展示给用户

                                          Spring-异常处理(9种讲解)

                                          • 可以看到,HandlerExceptionResolver接口中定义了一个名为resolveException的方法,该方法主要用于处理Controller中的异常
                                          • 参数“Exception ex”即为Controller或其下层抛出的异常
                                          • 参数“Object handler”就是处理器适配器要执行的Handler对象
                                          • resolveException方法的返回值类型是ModelAndView,也就是说,可以通过这个返回值来设置发送异常时的显示页面
                                            • 典型的做法是转换成一个错误视图,或者返回某个HTTP状态码给请求端
                                            • 使用HandlerExceptionResolver实现全局异常处理器;当抛出异常后,要有相应的符合用户体验的友好界面显示异常
                                            • 综合实例:
                                            • (1)创建自定义异常类,名称为OperationException

                                              Spring-异常处理(9种讲解)

                                              • 注意:
                                              • Spring管理的事务,无论是声明式事务还是注解式事务默认是在抛出运行异常(RuntimeException异常)时,才会被Spring框架捕获到然后回滚
                                              • 该自定义异常类继承的是RuntimeException类,因为一般项目的Service层逻辑都会使用Spring提供的事务管理,当Service层需要抛出自定义异常时,如果该自定义异常继承的是Exception类,则Spring提供的事务管理将会失效,所以这里的自定义异常类继承的是RuntimeException类,这样才不会使Spring提供的事务管理失效
                                              • (2)创建全局异常处理器OperationExceptionResolver类,该类实现HandlerExceptionResolver接口,并且实现resolveException方法

                                                Spring-异常处理(9种讲解)

                                                • (3)创建名称为error.jsp的页面,符合用户体验的友好界面,用于显示异常信息
                                                  • Spring MVC 为HandlerExceptionResolver提供了四个实现类:

                                                    (1)ExceptionHandlerExceptionResolver

                                                    • 该解析器是在 Spring 3.1 中引入的,并且在DispatcherServlet中默认启用
                                                    • 这实际上是前面介绍的@ExceptionHandler机制如何工作的核心组件
                                                    • 找到使用@ExceptionHandler注解的ServletInvocableHandlerMethod并调用,基于其执行结果构建ModelAndView

                                                      (2)SimpleMappingExceptionResolver

                                                      • 映射异常类名到视图名称,处理时使用此映射关系构建ModelAndView,或者使用缺省视图

                                                        (3)ResponseStatusExceptionResolver

                                                        • 这个解析器也在 Spring 3.0 中引入,并且在DispatcherServlet中默认启用
                                                        • 如果异常是ResponseStatusException或者使用了注解@ResponseStatus,则利用这些信息将异常翻译成HTTP状态字调用相应的sendError,返回空ModelAndView(与DefaultHandlerExceptionResolver相同,此解析器在处理响应正文的方式上受到限制 - 它确实将状态代码映射到响应上,但正文仍然为空)
                                                        • 这样的自定义异常可能如下所示:
                                                        • Spring-异常处理(9种讲解)
                                                        • 注意:该异常解析器会递归检查异常的cause异常

                                                          (4)DefaultHandlerExceptionResolver

                                                          • 这个解析器是在 Spring 3.0 中引入的,并且在DispatcherServlet中默认启用
                                                          • Spring MVC缺省异常处理器,解析时将标准MVC异常翻译成HTTP状态字调用相应对象的方法#sendError,返回一个空ModelAndView对象(注意:不是null)
                                                          • 它用于将标准 Spring 异常解析为相应的 HTTP 状态代码,即客户端错误4xx和服务器错误5xx状态代码
                                                          • 虽然它确实正确设置了响应的状态代码,但有一个限制是它不会对响应正文设置任何内容
                                                          • 对于 REST API(状态代码实际上不足以向客户端提供足够的信息),响应还必须有一个正文,以允许应用程序提供有关失败的附加信息
                                                          • 这可以通过ModelAndView配置视图分辨率并渲染错误内容来解决,但该解决方案显然不是最优的
                                                          • 这就是为什么 Spring 3.2 引入了一个更好的选项,我们将在后面的部分中讨论

                                                            使用注解实现异常分类管理(@ControllerAdvice 和 @ExceptionHandler)

                                                            • 引言:
                                                            • 在开发中,我们会有如下的场景:某个接口中,存在一些业务异常
                                                            • 例如用户输入的参数校验失败、用户名密码不存在等
                                                            • 当触发这些业务异常时,我们需要抛出这些自定义的业务异常,并对其进行处理
                                                            • 一般我们要把这些异常信息的状态码和异常描述,友好地返回给调用者,调用者则利用状态码等信息判断异常的具体情况
                                                            • 过去,我们可能需要在 controller 层通过 try/catch 处理
                                                            • 首先 catch 自定义异常,然后 catch 其它异常
                                                            • 对于不同的异常,我们需要在 catch 的同时封装将要返回的对象
                                                            • 然而,这么做的弊端就是代码会变得冗长
                                                            • 每个接口都需要做 try/catch 处理,而且一旦需要调整,所有的接口都需要修改一遍,非常不利于代码的维护,如下段代码所示:

                                                              Spring-异常处理(9种讲解)

                                                              • 那么,有没有什么方法可以简便地处理这些异常信息呢?
                                                              • 答案是肯定的
                                                              • Spring 3.2 中,新增了 @ControllerAdvice 注解,可以用于定义 @ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有 @RequestMapping 中
                                                              • @ControllerAdvice注解允许我们将之前的多个分散的@ExceptionHandler合并到一个全局错误处理组件中
                                                              • 简单来说就是,可以通过 @ControllerAdvice 注解配置一个全局异常处理类,来统一处理 controller 层中的异常,于此同时 controller 中可以不用再写 try/catch,这使得代码既整洁又便于维护
                                                                • 综合实例:定义自定义异常
                                                                • (1)自定义业务异常类

                                                                  Spring-异常处理(9种讲解)

                                                                  • (2)@ControllerAdvice + @ExceptionHandler 配置全局异常处理类

                                                                    Spring-异常处理(9种讲解)

                                                                    @ControllerAdvice

                                                                    • 类型:类注解;定义该类为全局异常处理类

                                                                      @ExceptionHandler

                                                                      • 类型:方法注解;定义该方法为异常处理方法
                                                                      • value 的值为需要处理的异常类的 class 文件
                                                                        • 这样,就可以对不同的异常进行统一处理了
                                                                        • 通常,为了使 controller 中不再使用任何 try/catch,也可以在 GlobalExceptionHandler 中对 Exception 做统一处理
                                                                        • 这样其他没有用 @ExceptionHandler 配置的异常就都会统一被处理
                                                                        • 遇到异常时抛出异常即可
                                                                        • 在业务中,遇到业务异常的地方,直接使用 throw 抛出对应的业务异常即可
                                                                        • 例如:

                                                                          Spring-异常处理(9种讲解)


                                                                          注意:

                                                                          • 不一定必须在 controller 层本身抛出异常才能被 GlobalExceptionHandler 处理,只要异常最后是从 contoller 层抛出去的就可以被全局异常处理器处理
                                                                          • 异步方法中的异常不会被全局异常处理
                                                                          • 抛出的异常如果被代码内的 try/catch 捕获了,就不会被 GlobalExceptionHandler 处理了

                                                                            优点:

                                                                            • 减少代码冗余,代码便于维护

                                                                              缺点:

                                                                              • 只能处理 controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理

                                                                                使用 @ControllerAdvice 对不同的 Controller 分别捕获异常并处理

                                                                                • 引言
                                                                                • 上文介绍了如何在 SpringBoot 工程中对 Controller 配置全局异常处理
                                                                                • 后来在实际工程中,又有了如下需求:有些接口在发生异常时,需要持久化错误信息,而有的接口则不需要
                                                                                • 如果使用了全局异常处理,那每次发生了异常,还需要判断是哪个接口发生的异常,进而选择是否持久化错误日志
                                                                                • 那能不能对全局异常进行配置,对不同类型的接口使用不同的全局异常进行处理呢?
                                                                                • 经过查阅文档发现,Spring 提供了对 @ControllerAdvice 注解的配置,我们可以通过配置 @ControllerAdvice 指定拦截范围
                                                                                • @ControllerAdvice 指定 Controller 范围
                                                                                • 根据 API,我们可以看到注解 @ControllerAdvice 有如下几种配置:

                                                                                  (1)basePackages

                                                                                  Spring-异常处理(9种讲解)

                                                                                  • basePackages:指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理
                                                                                  • 其中上面两种等价于 basePackages

                                                                                    (2)basePackageClasses

                                                                                    Spring-异常处理(9种讲解)

                                                                                    • basePackageClasses:是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理

                                                                                      (3)assignableTypes

                                                                                      Spring-异常处理(9种讲解)

                                                                                      • assignableTypes:指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理

                                                                                        (4)annotations

                                                                                        Spring-异常处理(9种讲解)

                                                                                        • annotations:指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理
                                                                                          • 例子
                                                                                          • 这里用 assignableTypes 配置指定的 Controller 进行测试

                                                                                            (1)创建三个 Controller

                                                                                            • Spring-异常处理(9种讲解)
                                                                                            • Spring-异常处理(9种讲解)
                                                                                            • Spring-异常处理(9种讲解)
                                                                                            • 其中,BusinessException 是自定义的异常类

                                                                                              (2)创建两个全局异常处理类

                                                                                              • Spring-异常处理(9种讲解)
                                                                                              • Spring-异常处理(9种讲解)

                                                                                                (3)分别调用接口,查看错误日志

                                                                                                • (1)调用 localhost:8080/test1

                                                                                                • 返回:GlobalExceptionHandler1 服务错误

                                                                                                • 即 MyController1 异常被 GlobalExceptionHandler1 全局异常类捕获

                                                                                                • (2)调用 localhost:8080/test2

                                                                                                • 返回:GlobalExceptionHandler2 服务错误

                                                                                                • 即 MyController2 异常被 GlobalExceptionHandler2 全局异常类捕获

                                                                                                • (3)调用 localhost:8080/test3

                                                                                                • 返回:

                                                                                                • Spring-异常处理(9种讲解)

                                                                                                • 即 MyController3 异常没有被全局异常捕获

                                                                                                  ResponseStatusException(Spring 5及以上版本)

                                                                                                  • Spring 5 引入了ResponseStatusException类
                                                                                                  • Spring-异常处理(9种讲解)

                                                                                                    使用ResponseStatusException有什么好处?

                                                                                                    • 非常适合原型设计:我们可以非常快速地实施基本解决方案
                                                                                                    • 一种类型,多个状态代码:一种异常类型可以导致多种不同的响应;与@ExceptionHandler相比,这减少了紧密耦合
                                                                                                    • 我们不必创建那么多自定义异常类
                                                                                                    • 由于可以通过编程方式创建异常,因此我们可以更好地控制异常处理

                                                                                                      坏处:

                                                                                                      • 没有统一的异常处理方法:与提供全局处理方法的@ControllerAdvice相比,强制执行一些应用程序范围的约定更加困难
                                                                                                      • 代码重复:我们可能会发现自己在多个控制器中复制代码
                                                                                                        • 我们还应该注意到,可以在一个应用程序中组合不同的方法
                                                                                                        • 例如,我们可以全局实现 @ControllerAdvice,也可以在本地实现ResponseStatusException

                                                                                                          Spring Web MVC 中的异常处理流程

                                                                                                          • DispatcherServlet 类处理多个 HandlerExceptionResolver 对象
                                                                                                          • 提供了ExceptionHandlerExceptionResolver类、ResponseStatusExceptionResolver类和DefaultHandlerExceptionResolver类,这些类各司其职,处理异常
                                                                                                          • 其中 ExceptionHandlerExceptionResolver 类负责调用@ExceptionHandler注解的方法
                                                                                                          • DispatcherServlet(Spring 框架 5.1.9.RELEASE API)
                                                                                                          • 调度程序的异常解决策略可以通过 HandlerExceptionResolver 指定,例如将某些异常映射到错误页面
                                                                                                          • 默认为 ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver 和 DefaultHandlerExceptionResolver
                                                                                                          • 这些 HandlerExceptionResolver 可以通过应用程序上下文覆盖
                                                                                                          • HandlerExceptionResolver 可以给定任何 bean 名称(它们是按类型测试)
                                                                                                          • 查看Spring Web MVC的DispatcherServlet类的源代码:
                                                                                                          • Spring-异常处理(9种讲解)
                                                                                                          • processHandlerException方法中,从this.handlerExceptionResolvers中---获取HandlerExceptionResolver对象,并调用resolveException方法
                                                                                                          • 每个对象的resolveException方法处理异常并返回一个ModelAndView对象
                                                                                                          • 查看 IntelliJ IDEA 调试器中正在处理的对象:
                                                                                                          • Spring-异常处理(9种讲解)
                                                                                                          • Spring-异常处理(9种讲解)
                                                                                                          • 可以看到HandlerExceptionResolverComposite对象管理着ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
                                                                                                          • ExceptionHandlerExceptionResolver对象有一个名为ExceptionHandlerAdviceCache的实例变量,它包含带有@ControllerAdvice注解的类的对象
                                                                                                          • 如果查看ExceptionHandlerExceptionResolver的源码,可以看到它是注册在ExceptionHandlerAdviceCache中的
                                                                                                          • Spring-异常处理(9种讲解)
                                                                                                          • Spring-异常处理(9种讲解)

免责声明
本网站所收集的部分公开资料来源于AI生成和互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复: 表情:
评论列表 (暂无评论,人围观)

还没有评论,来说两句吧...

目录[+]