组团学

SpringBoot异常处理和退出

阅读 (5344821)

1、自定义错误页面

1.1、概述

SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制。
一旦程序中出现了异常 SpringBoot 会向/error 的 url 发送请求。在 springBoot 中提供了一个叫 BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。

1.2、自定义错误页面

在src/main/resources/templates 目录下创建 error.html 页面

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 出错了,请与管理员联系。。。 </body> </html>

**注意:**名称必须叫 error,工程中要添加thymeleaf依赖

2、@ExceptionHandler 注解处理局部异常

2.1、Controller

@Controller public class HelloController { @GetMapping("/hello") public String hello(){ int result=10/0; return "index"; } /** * java.lang.ArithmeticException * 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视 图的指定 * 参数 Exception e:会将产生异常对象注入到方法中 */ @ExceptionHandler(value={java.lang.ArithmeticException.class}) public ModelAndView arithmeticExceptionHandler(Exception e){ ModelAndView mv = new ModelAndView(); mv.addObject("error", e.toString()); mv.setViewName("error"); return mv; } }

2.2、修改error.html

<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>错误页面</title> </head> <body> <span th:text="${error}"></span>,请与管理员联系...... </body> </html>

3、处理全局异常

3.1、@ControllerAdvice+@ExceptionHandler:

@ControllerAdvice public class GlobalException { /** * java.lang.ArithmeticException * 该方法需要返回一个 ModelAndView:目的是可以让我们封装异常信息以及视 图的指定 * 参数 Exception e:会将产生异常对象注入到方法中 */ @ExceptionHandler(value={java.lang.ArithmeticException.class}) public ModelAndView arithmeticExceptionHandler(Exception e){ ModelAndView mv = new ModelAndView(); mv.addObject("error", e.toString()); mv.setViewName("error"); return mv; } }

3.2、配置 SimpleMappingExceptionResolver 处理异常

在全局异常类中添加一个方法完成异常的统一处理,代码如下:

@Configuration public class GlobalException { /** * 该方法必须要有返回值。返回值类型必须是: * SimpleMappingExceptionResolver */ @Bean public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver() { SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver(); Properties mappings = new Properties(); /** * 参数一:异常的类型,注意必须是异常类型的全名 * 参数二:视图名称 */ mappings.put("java.lang.ArithmeticException", "error"); //设置异常与视图映射信息的 resolver.setExceptionMappings(mappings); return resolver; } }

3.3、自定义 HandlerExceptionResolver 类处理异常

在全 局 异 常 处 理 类 中 实 现HandlerExceptionResolver 接口,代码如下:

@Configuration public class GlobalException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView mv = new ModelAndView(); //判断不同异常类型,做不同视图跳转 if(ex instanceof ArithmeticException){ mv.setViewName("error"); } mv.addObject("error", ex.toString()); return mv; } }

4、Spring Boot 应用正常退出

查看SpringApplication源码

public class SpringApplication { ...... //退出方法 public static int exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators) { //断言conext不能为null Assert.notNull(context, "Context must not be null"); byte exitCode = 0; int exitCode; try { try { //创建退出码生成器 ExitCodeGenerators generators = new ExitCodeGenerators(); //从Spring容器中获取所有的退出码生成器实例 Collection<ExitCodeGenerator> beans = context.getBeansOfType(ExitCodeGenerator.class).values(); generators.addAll(exitCodeGenerators); generators.addAll(beans); //获得退出码 exitCode = generators.getExitCode(); //如果退出码不为0 if (exitCode != 0) { //发布退出码事件监听 context.publishEvent(new ExitCodeEvent(context, exitCode)); } } finally { close(context); } } catch (Exception var9) { var9.printStackTrace(); exitCode = exitCode != 0 ? exitCode : 1; } //返回退出码 return exitCode; } }

案例:

验证程序退出时ExitCodeGenerators的getExitCode()方法执行了

@EnableAutoConfiguration public class ExiteCodeGeneratorBootstrap { @Bean public ExitCodeGenerator exitCodeGenerator(){ System.out.println("ExitCodeGenerator Bean 创建..."); return ()->{ System.out.println("执行退出码88"); return 88; }; } public static void main(String[] args) { //在非Web应用中退出 SpringApplication.exit(new SpringApplicationBuilder(ExiteCodeGeneratorBootstrap.class) .web(WebApplicationType.NONE) .run(args)); } }

5、Spring Boot应用异常退出

源码:

private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) { try { try { //处理退出码 this.handleExitCode(context, exception); //如果Spring应用运行监听器不为null if (listeners != null) { //监听异常退出 listeners.failed(context, exception); } } finally { //报告错误 this.reportFailure(exceptionReporters, exception); //关闭Spring 上下文 if (context != null) { context.close(); } } } catch (Exception var9) { logger.warn("Unable to close ApplicationContext", var9); } ReflectionUtils.rethrowRuntimeException(exception); } //退出码处理方法 private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) { //从异常中获取退出码 int exitCode = this.getExitCodeFromException(context, exception); if (exitCode != 0) { if (context != null) { //如果退出码不为0,context不为null,发布退出码事件监听 context.publishEvent(new ExitCodeEvent(context, exitCode)); } //获取SpringBoot异常处理器 SpringBootExceptionHandler handler = this.getSpringBootExceptionHandler(); if (handler != null) { //如果处理器不为null,注册退出码 handler.registerExitCode(exitCode); } } } //从异常中获得退出码 private int getExitCodeFromException(ConfigurableApplicationContext context, Throwable exception) { //从MappedException获得退出码 int exitCode = this.getExitCodeFromMappedException(context, exception); //如果exitCode==0 if (exitCode == 0) { //从异常退出码生成器中获取退出码 exitCode = this.getExitCodeFromExitCodeGeneratorException(exception); } //退出码 return exitCode; } private int getExitCodeFromExitCodeGeneratorException(Throwable exception) { //如果exception==null,直接返回0 if (exception == null) { return 0; } else { //从退出码生成器中获得退出码 return exception instanceof ExitCodeGenerator ? ((ExitCodeGenerator)exception).getExitCode() : this.getExitCodeFromExitCodeGeneratorException(exception.getCause()); } }

由源码可知当异常实现ExitCodeGenerator接口时,退出码直接采用getExitCode()方法返回。

需要 登录 才可以提问哦