ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

《SpringBoot 3:入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 12

《SpringBoot 3:入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 12 《SpringBoot 3入门与应用实战》第 6 章 Spring Boot 最佳实践 阅读笔记 126.7 启动异常分析我们在开发应用的过程中几乎无法避免遇到各种错误和异常小到端口冲突大到内存泄漏等。6.7.1 FailureAnalyzer正常情况下当应用运行过程中出现异常时由抛出方逐层向上传递直至由 catch 块捕获或者在没有捕获时最终抛出并打印Spring Boot 提供的异常分析机制相当于从 catch 层切入它提供了一个核心组件 FailureAnalyzer 和一组实现以拦截应用启动过程中抛出的异常并尝试处理。FailureAnalyzer 本身是一个接口它来自 Spring Boot 1.4由于该接口中只有一个方法因此在 Spring Boot 2.0 中被声明为函数式接口。接口的设计非常简洁参数是 Throwable 对象经过 analyze 方法处理后转换为一个 FailureAnalysis 对象FailureAnalysis 的结构其实就是 Throwable 的包装额外添加了可以自行填写内容的 description 和 action 属性以便每个异常分析器 (FailureAnalyzer) 描述自己负责的异常以及出现该异常时的检查和修复建议动作。Spring Boot 内置了很多 FailureAnalyzer 的实现它们被定义在 META-INF/spring.factories 文件中。当应用启动时Spring Boot 会加载这个文件并将声明的所有 FailureAnalyzer 注册到 IOC 容器中以备后续启动过程中出现异常时做出反应。以端口号被占用的异常为例可以在 spring.factories 文件的 FailureAnalyzer 配置项中找到一个实现类 PortInUseFailureAnalyzer它可以识别和分析端口号被占用的问题。经查看它的源码可以发现它处理异常的方式非常简单就是把被占用的端口号取出并封装为异常报告信息生成 FailureAnalysis 对象。这就意味着只要在启动过程中抛出了 PortInUseException 异常PortInUseFailureAnalyzer 就可以将其捕获并封装异常分析信息。6.7.2 重写内置的异常分析Spring Boot 提供的内置异常分析组件很多开发人员通过读取异常分析信息可以相对简单地了解启动异常和定位但如果交给对日志不很了解的运维人员可能就不是很友好。为了解决该问题可以针对内置组件中不易理解和获取错误定位的异常进行重写通过重写异常分析信息提供更易理解的错误提示和修复指导。以 6.7 节的端口号被占用为例如果我们需要重写端口被占用时的异常提示信息可以编写一个新的类ChinesePortInUseFailureAnalyzer基于中文的端口号被占用分析器使其继承 FailureAnalyzer 的抽象父类AbstractFailureAnalyzer并指定捕获的异常类型为 PortInUseException即可在 analyze 方法中获取该异常并自行封装 FailureAnalysis 信息。packagecom.yangjunbo.springboot.practice.examplee;importorg.springframework.boot.diagnostics.AbstractFailureAnalyzer;importorg.springframework.boot.diagnostics.FailureAnalysis;importorg.springframework.boot.web.server.PortInUseException;publicclassChinesePortInUseFailureAnalyzerextendsAbstractFailureAnalyzerPortInUseException{OverrideprotectedFailureAnalysisanalyze(ThrowablerootFailure,PortInUseExceptioncause){returnnewFailureAnalysis(当前端口cause.getPort()被占用,检查cause.getPort()为什么被占用并停止占用的程序。,rootFailure);}}要想让自己编写的异常分析器生效需要遵循 Spring Boot 的规则将 hinesePortIn UseFailureAnalyzer 配置到 spring.factories 文件的 FailureAnalyzer 配置项中所以接下来在 resources/META-INF 目录下创建 spring.factories 文件。org.springframework.boot.diagnostics.FailureAnalyzer\ com.yangjunbo.springboot.practice.examplee.ChinesePortInUseFailureAnalyzer如此编写完毕后下面重启应用测试效果。和预期一致工程启动失败但是控制台中打印的异常分析信息变为编写的中文内容说明自行编写的异常分析器可以覆盖 Spring Boot 内置的组件。6.7.3 自定义异常分析随着应用的不断开发在应用启动阶段可能会添加新的扩展逻辑伴随这些扩展逻辑的添加可能会有一些校验逻辑附加到启动阶段。为了能在校验失败时提供更易读的错误报告和修改提示可以自定义校验的异常以及为这些异常制定异常分析规则。使用一个比较简单的场景作为示例。自定义的异常场景是当应用启动的端口号被设置为 5 位数时抛出异常终止程序运行。首先定义一个新的运行时异常类 IllegalPortException使其继承 Runtime Exception 并在内部声明一个 int 类型的变量用于接收不合法的端口号。packagecom.yangjunbo.springboot.practice.examplef;/** * 不合法的端口异常 */publicclassIllegalPortExceptionextendsRuntimeException{privateintport;publicIllegalPortException(intport){this.portport;}publicintgetPort(){returnport;}}为了能在应用启动阶段将该异常抛出可以借助 6.5.4 节中学习的 CommandLineRunner 接口来触发声明一个 IllegalPortChecker 类实现CommandLineRunner 接口并标注 Component 注解随后实现端口检测逻辑。注意Value 注解中使用的占位符考虑了未声明 server.port的情况。packagecom.yangjunbo.springboot.practice.examplef;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.CommandLineRunner;importorg.springframework.stereotype.Component;ComponentpublicclassIllegalPortCheckerimplementsCommandLineRunner{Value(${server.port:8080})privateintport;Overridepublicvoidrun(String...args){if(port10000){thrownewIllegalPortException(port);}}}接下来是与 IllegalPortException 异常对应的异常分析器仿照 Spring Boot 的编写风格可以快速编写出相对应的 IllegalPortFailureAnalyzer。packagecom.yangjunbo.springboot.practice.examplef;importorg.springframework.boot.diagnostics.AbstractFailureAnalyzer;importorg.springframework.boot.diagnostics.FailureAnalysis;publicclassIllegalPortFailureAnalyzerextendsAbstractFailureAnalyzerIllegalPortException{OverrideprotectedFailureAnalysisanalyze(ThrowablerootFailure,IllegalPortExceptioncause){returnnewFailureAnalysis(检测到不合法的端口cause.getPort(),请使用10000以内的端口号,cause);}}最后将 IllegalPortFailureAnalyzer 配置到 spring.factories 文件中即可完成全部工作。org.springframework.boot.diagnostics.FailureAnalyzer\ com.yangjunbo.springboot.practice.examplee.ChinesePortInUseFailureAnalyzer,\ com.yangjunbo.springboot.practice.examplef.IllegalPortFailureAnalyzer这个 \ 符号在 Java 的配置文件中叫做续行符Line Continuation Character。它的作用非常简单告诉解析器当前行还没有结束下一行是当前行的延续。全部编码工作完成后修改 application-dev.properties 文件中 server.port 的值为 18080并重新运行工程这次虽然不会提示端口冲突但由于使用的端口号 “不合法”​导致 IllegalPortException 异常被抛出最终控制台会打印如下错误报告证明自定义的异常报告组件已经生效。6.8 小结Spring Boot 之所以强大其可配置性和高扩展性必定占有一席之地。通过使用 properties 或 YML 格式的文件声明配置并辅以 Profile 特性可以轻松地定义多套不同运行环境下的配置结合属性绑定功能将配置文件中的配置属性映射到特定的属性模型类中可以方便地管理和使用这些配置属性。Spring Boot 的日志体系天然集成在官方的场景启动器中默认使用 Slf4j Logback 的日志门面实现组合借助 Spring Boot 的整合能力可以直接在全局配置文件中自定义日志的输出格式、日志载体、日志级别等。Spring Boot 中可以切入的扩展点非常多从启动容器前到容器初始化阶段再到应用启动完成后的一系列过程都有非常多的切入点。Spring Boot 快速搭建工程的秘籍之一是场景启动器场景启动器中包含一个应用开发场景中所需的全部依赖和相关的配置自行制作场景启动器时也需要将这些因素全部考虑进去。对于应用启动过程中出现异常的问题Spring Boot 通过启动异常分析机制将异常捕获并转换为可读的错误提示和修复建议帮助开发者排查问题针对应用中扩展的功能也可以提前考虑潜在的问题并编写相应的自定义异常和分析器以提供更友好的提示信息。
返回列表