SpringBoot自定义FailureAnalyzer
官网说明
1.1 创建自己的 FailureAnalyzer
FailureAnalyzer是一种在启动时拦截 exception 并将其转换为 human-readable 消息的好方法,包含在故障分析中。 Spring Boot 为 application context 相关的 exceptions,JSR-303 验证等提供了这样的分析器。实际上很容易创建自己的。
AbstractFailureAnalyzer
是FailureAnalyzer
的方便扩展,它检查 exception 中是否存在指定的 exception 类型来处理。你可以从中扩展,这样你的 implementation 只有在它实际存在时才有机会处理 exception。如果由于某种原因你无法处理 exception,return null
给另一个 implementation 一个处理 exception 的机会。
FailureAnalyzer
__mplement 将在META-INF/spring.factories
中注册:以下寄存器ProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
1.2 排除故障 auto-configuration
Spring Boot auto-configuration 尽力'做正确的事',但有时事情会失败,而且很难说出原因。
在 Spring Boot ApplicationContext
中有一个非常有用的ConditionEvaluationReport
可用。如果启用DEBUG
logging 输出,您将看到它。如果使用spring-boot-actuator
,还有一个端点,用 JSON 呈现报表。使用它来调试 application 并查看 Spring Boot 在运行时添加了哪些 features(以及哪些没有)。
通过查看 source code 和 Javadoc 可以回答更多问题。一些经验法则:
查找名为
*AutoConfiguration
的 classes 并读取它们的源,特别是@Conditional*
注释,以找出它们启用的 features 和何时启用。将--debug
添加到命令 line 或 System property-Ddebug
以在 console 上添加 log 在您的应用程序中做出的所有 auto-configuration 决策。在 running Actuator 应用程序中,查看autoconfig
端点('/autoconfig'或 JMX 等效项)以获取相同的信息。查找
@ConfigurationProperties
(e.g. ServerProperties)的 classes 并从那里读取可用的外部 configuration 选项。@ConfigurationProperties
有一个name
属性,作为外部 properties 的前缀,因此ServerProperties
有prefix="server"
,其 configuration properties 是server.port
,server.address
等。在 running Actuator 应用程序中查看configprops
端点。寻找使用
RelaxedPropertyResolver
从Environment
中明确地提取 configuration 值。它通常与前缀一起使用。查找直接绑定到
Environment
的@Value
注释。这不如RelaxedPropertyResolver
方法灵活,但允许一些轻松的 binding,特别是 OS 环境变量(因此CAPITALS_AND_UNDERSCORES
是period.separated
的同义词)。查找
@ConditionalOnExpression
注释,以响应 SpEL 表达式打开和关闭 features,通常使用从Environment
解析的占位符进行评估。
1.3 在启动之前自定义 Environment 或 ApplicationContext
SpringApplication
具有ApplicationListeners
和ApplicationContextInitializers
,用于将自定义应用于 context 或环境。 Spring Boot 加载了许多此类自定义项,以便在META-INF/spring.factories
内部使用。注册其他方法的方法不止一种:
通过在_运行之前调用
SpringApplication
上的addListeners
和addInitializers
方法,以编程方式为每个 application。通过设置
context.initializer.classes
或context.listener.classes
来声明每个 application。通过添加
META-INF/spring.factories
并打包_appar 全部用作 library 的 jar 文件来声明所有 applications。
SpringApplication
向 listeners 发送一些特殊的ApplicationEvents
(甚至在创建 context 之前的一些),然后为ApplicationContext
发布的 events 注册 listeners
在使用EnvironmentPostProcessor
刷新 application context 之前,还可以自定义Environment
。每个 implementation 都应该在META-INF/spring.factories
中注册:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
implementation 可以加载任意 files 并将它们添加到Environment
。例如,此 example 从 classpath 加载 YAML configuration 文件:
public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor { private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader(); @Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
Resource path = new ClassPathResource("com/example/myapp/config.yml");
PropertySource<?> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
} private PropertySource<?> loadYaml(Resource path) {
if (!path.exists()) {
throw new IllegalArgumentException("Resource " + path + " does not exist");
}
try {
return this.loader.load("custom-resource", path, null);
}
catch (IOException ex) {
throw new IllegalStateException(
"Failed to load yaml configuration from " + path, ex);
}
} }
Environment
已经准备好了 Spring Boot 默认加载的所有常用 property 源。因此,可以从环境中获取文件的位置。此 example 在列表末尾添加custom-resource
property 源,以便在任何其他常用位置中定义的 key 优先。自定义 implementation 显然可以定义另一个 order。
虽然在
@SpringBootApplication
上使用@PropertySource
似乎方便且容易在Environment
中加载自定义资源,但我们不推荐它为 Spring Boot 在ApplicationContext
刷新之前准备Environment
。通过@PropertySource
定义的任何 key 都将被加载太晚而不会对 auto-configuration 产生任何影响。
代码示例
2.1 指定异常分析
SpringBoot
内部提供的启动异常分析都是指定具体的异常类型实现的,最常见的一个错误就是端口号被占用(PortInUseException
),虽然SpringBoot
内部提供一个这个异常的启动分析,我们也是可以进行替换这一异常分析的,我们只需要创建PortInUseException
异常的AbstractFailureAnalyzer
,并且实现类注册给SpringBoot
即可,实现自定义如下所示
/**
* @author WGR
* @create 2019/11/24 -- 23:00
*/
public class PortInUseFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(PortInUseFailureAnalyzer.class); @Override
protected FailureAnalysis analyze(Throwable rootFailure, PortInUseException cause) {
logger.error("端口被占用。", cause);
return new FailureAnalysis("端口号:" + cause.getPort() + "被占用", "PortInUseException", rootFailure);
}
}
注册启动异常分析
在上面我们只是编写了指定异常启动分析,我们接下来需要让它生效,这个生效方式比较特殊,类似于自定义SpringBoot Starter AutoConfiguration
的形式,我们需要在META-INF/spring.factories
文件内进行定义,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.topcheer.activiti.analyzer.PortInUseFailureAnalyzer
那我们为什么需要使用这种方式定义呢?
项目启动遇到的异常顺序不能确定,很可能在Spring IOC
并未执行初始化之前就出现了异常,我们不能通过@Component
注解的形式使其生效,所以SpringBoot
提供了通过spring.factories
配置文件的方式定义。
测试:启动2个8080端口
启动异常分析继承关系
自定义的运行异常一般都是继承自RuntimeException
,如果我们定义一个RuntimeException
的异常启动分析实例会是什么效果呢?
public class ProjectBootUnifiedFailureAnalyzer extends AbstractFailureAnalyzer<RuntimeException> {
/**
* logger instance
*/
static Logger logger = LoggerFactory.getLogger(ProjectBootUnifiedFailureAnalyzer.class); @Override
protected FailureAnalysis analyze(Throwable rootFailure, RuntimeException cause) {
logger.error("遇到运行时异常", cause);
return new FailureAnalysis(cause.getMessage(), "error", rootFailure);
}
}
将该类也一并注册到spring.factories
文件内,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.topcheer.activiti.analyze.PortInUseFailureAnalyzer,\
com.topcheer.activiti.analyze.ProjectBootUnifiedFailureAnalyzer
运行项目并测试端口号被占用异常
我们会发现,并没有执行ProjectBootUnifiedFailureAnalyzer
内的analyze
方法,而是继续执行了PortInUseFailureAnalyzer
类内的方法。
那我们将PortInUseFailureAnalyzer
这个启动分析从spring.factories
文件内暂时删除掉
,再来运行项目我们会发现这时却是会执行ProjectBootUnifiedFailureAnalyzer
类内分析方法。
总结
根据本章我们了解了SpringBoot
提供的启动异常分析接口以及基本抽象实现类的运作原理,而且启动异常分析存在分析泛型异常类的上下级继承关系,异常子类的启动分析会覆盖掉异常父类的启动分析,如果你想包含全部异常的启动分析可以尝试使用Exception
作为AbstractFailureAnalyzer
的泛型参数。
参考链接:https://www.jianshu.com/p/e9dc0ee91b26
SpringBoot自定义FailureAnalyzer的更多相关文章
- SpringBoot自定义拦截器实现IP白名单功能
SpringBoot自定义拦截器实现IP白名单功能 转载请注明源地址:http://www.cnblogs.com/funnyzpc/p/8993331.html 首先,相关功能已经上线了,且先让我先 ...
- SpringBoot自定义错误信息,SpringBoot适配Ajax请求
SpringBoot自定义错误信息,SpringBoot自定义异常处理类, SpringBoot异常结果处理适配页面及Ajax请求, SpringBoot适配Ajax请求 ============== ...
- SpringBoot自定义错误页面,SpringBoot 404、500错误提示页面
SpringBoot自定义错误页面,SpringBoot 404.500错误提示页面 SpringBoot 4xx.html.5xx.html错误提示页面 ====================== ...
- springboot自定义错误页面
springboot自定义错误页面 1.加入配置: @Bean public EmbeddedServletContainerCustomizer containerCustomizer() { re ...
- SpringBoot自定义Filter
SpringBoot自定义Filter SpringBoot自动添加了OrderedCharacterEncodingFilter和HiddenHttpMethodFilter,当然我们可以自定 义F ...
- springboot 自定义LocaleResolver切换语言
springboot 自定义LocaleResolver切换语言 我们在做项目的时候,往往有很多项目需要根据用户的需要来切换不同的语言,使用国际化就可以轻松解决. 我们可以自定义springboor中 ...
- SpringMVC拦截器与SpringBoot自定义拦截器
首先我们先回顾一下传统拦截器的写法: 第一步创建一个类实现HandlerInterceptor接口,重写接口的方法. 第二步在XML中进行如下配置,就可以实现自定义拦截器了 SpringBoot实现自 ...
- [技术博客] SPRINGBOOT自定义注解
SPRINGBOOT自定义注解 在springboot中,有各种各样的注解,这些注解能够简化我们的配置,提高开发效率.一般来说,springboot提供的注解已经佷丰富了,但如果我们想针对某个特定情景 ...
- SpringBoot --- 自定义 Starter
SpringBoot --- 自定义 Starter 创建 1.需要创建一个新的空工程 2.新的工程需要引入两个模块 一个Maven 模块 作为启动器 一个SpringBoot 模块 作为自动配置模块 ...
随机推荐
- PHP操作SESSION
说一下在PHP里面怎么简单的操作SESSION 操作SESSION流程 <?php session_start(); //开启session $_SESSION['user']='admin'; ...
- 修改jupyter notebook默认路径,亲测
anaconda环境 任务栏中找到anaconda/jupyter notebook,鼠标右键属性 点击确认即可.
- IDEA中解决 git pull 冲突
0.事先准备.1)把远程仓库的README.md内容改写为bbb(原先为aaa). 2)本地仓库的README.md内容改写为ccc(原先也为aaa). 以此来模仿代码冲突. 1.先commit ...
- linux rz上传-sz下载
yum install lrzsz -y rz 上传文件 不能传目录 如果要传目录需要打包成文件再上传 需要往哪里传东西,先进入哪个目录 rz -y 上传覆盖 sz -y 文件名 ...
- Nginx日志监控 使用 goaccess查看nginx日志
nginx日志监控 yum install goaccess 安装使用教程 goaccess access.log -o ../html/report.html --real-time-html ...
- [转帖]IIS7.5应用程序池集成模式和经典模式的区别介绍
IIS7.5应用程序池集成模式和经典模式的区别介绍 之前转帖过一个 但是感觉不如这个说的细: https://www.jb51.net/article/31010.htm 关注脚本之家微信公众号(jb ...
- Luogu P5330 [SNOI2019]数论
题目 如果\(P>Q\)的话我们先交换一下\(P,Q\). 我们先枚举所有满足第一个条件的数,对于\(x\equiv a_i(mod\ P)\),设\(x=a_i+kP(k\in[0,\lflo ...
- Gym 101986D Making Perimeter of the Convex Hull Shortest(凸包+极角排序)
首先肯定是构造一个完整的凸包包括所有的点,那么要使得刚好有两个点在外面,满足这个条件的只有三种情况. 1.两个在凸包上但是不连续的两个点. 2.两个在凸包上但是连续的两个点. 3.一个在凸包上,还有一 ...
- 分布式理论: CAP、BASE (转)
分布式系统的CAP理论是由Eric Brewer于1999年首先提出的,又被称作布鲁尔定理(Brewer's theorem),CAP是对Consistency(一致性).Availability(可 ...
- django报错处理:对应ip无法登陆与使用bootstrap移动端响应工具,head响应实例
1.报错 Invalid HTTP_HOST header: '192.168.1.100:8000'. You may need to add '192.168.1.100' to ALLOWED_ ...