SpringBoot自定义FailureAnalyzer过程解析
这篇文章主要介绍了SpringBoot自定义FailureAnalyzer,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
官网说明
1.1创建自己的FailureAnalyzer
FailureAnalyzer是一种在启动时拦截exception并将其转换为human-readable消息的好方法,包含在故障分析中。SpringBoot为applicationcontext相关的exceptions,JSR-303验证等提供了这样的分析器。实际上很容易创建自己的。
AbstractFailureAnalyzer是FailureAnalyzer的方便扩展,它检查exception中是否存在指定的exception类型来处理。你可以从中扩展,这样你的implementation只有在它实际存在时才有机会处理exception。如果由于某种原因你无法处理exception,returnnull给另一个implementation一个处理exception的机会。
FailureAnalyzer__mplement将在META-INF/spring.factories中注册:以下寄存器ProjectConstraintViolationFailureAnalyzer:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.example.ProjectConstraintViolationFailureAnalyzer
1.2排除故障auto-configuration
SpringBootauto-configuration尽力'做正确的事',但有时事情会失败,而且很难说出原因。
在SpringBootApplicationContext中有一个非常有用的ConditionEvaluationReport可用。如果启用DEBUGlogging输出,您将看到它。如果使用spring-boot-actuator,还有一个端点,用JSON呈现报表。使用它来调试application并查看SpringBoot在运行时添加了哪些features(以及哪些没有)。
通过查看sourcecode和Javadoc可以回答更多问题。一些经验法则:
- 查找名为*AutoConfiguration的classes并读取它们的源,特别是@Conditional*注释,以找出它们启用的features和何时启用。将--debug添加到命令line或Systemproperty-Ddebug以在console上添加log在您的应用程序中做出的所有auto-configuration决策。在runningActuator应用程序中,查看autoconfig端点('/autoconfig'或JMX等效项)以获取相同的信息。
- 查找@ConfigurationProperties(e.g.ServerProperties)的classes并从那里读取可用的外部configuration选项。@ConfigurationProperties有一个name属性,作为外部properties的前缀,因此ServerProperties有prefix="server",其configurationproperties是server.port,server.address等。在runningActuator应用程序中查看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或环境。SpringBoot加载了许多此类自定义项,以便在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刷新applicationcontext之前,还可以自定义Environment。每个implementation都应该在META-INF/spring.factories中注册:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
implementation可以加载任意files并将它们添加到Environment。例如,此example从classpath加载YAMLconfiguration文件:
publicclassEnvironmentPostProcessorExampleimplementsEnvironmentPostProcessor{ privatefinalYamlPropertySourceLoaderloader=newYamlPropertySourceLoader(); @Override publicvoidpostProcessEnvironment(ConfigurableEnvironmentenvironment, SpringApplicationapplication){ Resourcepath=newClassPathResource("com/example/myapp/config.yml"); PropertySource>propertySource=loadYaml(path); environment.getPropertySources().addLast(propertySource); } privatePropertySource>loadYaml(Resourcepath){ if(!path.exists()){ thrownewIllegalArgumentException("Resource"+path+"doesnotexist"); } try{ returnthis.loader.load("custom-resource",path,null); } catch(IOExceptionex){ thrownewIllegalStateException( "Failedtoloadyamlconfigurationfrom"+path,ex); } } }
Environment已经准备好了SpringBoot默认加载的所有常用property源。因此,可以从环境中获取文件的位置。此example在列表末尾添加custom-resourceproperty源,以便在任何其他常用位置中定义的key优先。自定义implementation显然可以定义另一个order。
虽然在@SpringBootApplication上使用@PropertySource似乎方便且容易在Environment中加载自定义资源,但我们不推荐它为SpringBoot在ApplicationContext刷新之前准备Environment。通过@PropertySource定义的任何key都将被加载太晚而不会对auto-configuration产生任何影响。
代码示例
2.1指定异常分析
SpringBoot内部提供的启动异常分析都是指定具体的异常类型实现的,最常见的一个错误就是端口号被占用(PortInUseException),虽然SpringBoot内部提供一个这个异常的启动分析,我们也是可以进行替换这一异常分析的,我们只需要创建PortInUseException异常的AbstractFailureAnalyzer,并且实现类注册给SpringBoot即可,实现自定义如下所示
/** *@authorWGR *@create2019/11/24--23:00 */ publicclassPortInUseFailureAnalyzerextendsAbstractFailureAnalyzer{ /** *loggerinstance */ staticLoggerlogger=LoggerFactory.getLogger(PortInUseFailureAnalyzer.class); @Override protectedFailureAnalysisanalyze(ThrowablerootFailure,PortInUseExceptioncause){ logger.error("端口被占用。",cause); returnnewFailureAnalysis("端口号:"+cause.getPort()+"被占用","PortInUseException",rootFailure); } }
注册启动异常分析
在上面我们只是编写了指定异常启动分析,我们接下来需要让它生效,这个生效方式比较特殊,类似于自定义SpringBootStarterAutoConfiguration的形式,我们需要在META-INF/spring.factories文件内进行定义,如下所示:
org.springframework.boot.diagnostics.FailureAnalyzer=\ com.topcheer.activiti.analyzer.PortInUseFailureAnalyzer
那我们为什么需要使用这种方式定义呢?
项目启动遇到的异常顺序不能确定,很可能在SpringIOC并未执行初始化之前就出现了异常,我们不能通过@Component注解的形式使其生效,所以SpringBoot提供了通过spring.factories配置文件的方式定义。
测试:启动2个8080端口
启动异常分析继承关系
自定义的运行异常一般都是继承自RuntimeException,如果我们定义一个RuntimeException的异常启动分析实例会是什么效果呢?
publicclassProjectBootUnifiedFailureAnalyzerextendsAbstractFailureAnalyzer{ /** *loggerinstance */ staticLoggerlogger=LoggerFactory.getLogger(ProjectBootUnifiedFailureAnalyzer.class); @Override protectedFailureAnalysisanalyze(ThrowablerootFailure,RuntimeExceptioncause){ logger.error("遇到运行时异常",cause); returnnewFailureAnalysis(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的泛型参数。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。