springboot之FailureAnalyzer
引
言
在这篇文章中,我们将探究springboot中的FailureAnalyzer(故障分析器),我们还将了解在springboot应用中创建自定义FailureAnalyzer。
介绍
大多数情况下,当我们在服务器启动时遇到异常时,我们需要非常仔细地分析,以便在尝试修复它之前理解出什么问题。
通过FailureAnalyzer,springboot提供了一种在启动时拦截异常的方法,并将它们转换为人性化的格式(不必翻阅整个异常堆栈信息)。springboot自带了许多从应用程序上下文相关异常开始的FailureAnalyzer故障分析器。
这里有一个例子,8080端口已经被使用,当我们试图在8080端口运行我们的springboot应用时,PortInUseFailureAnalyzer截获这个异常并提供了一个更具可读性和用户友好的错误消息。
*************************** APPLICATION FAILED TO START *************************** Description: The Tomcat connector configured to listen on port 8080 failed to start. The port may already be in use or the connector may be misconfigured. Action: Verify the connector's configuration, identify and stop any process that's listening on port 8080, or configure this application to listen on another port.
以下是springboot提供的几个常用的FailureAnalyzer列表:
- PortInUseFailureAnalyzer
- NoUniqueBeanDefinitionFailureAnalyzer
- BeanCurrentlyInCreationFailureAnalyzer
你可以通过查看springboot的org.springframework.boot.diagnostics包找到完整的FailureAnalyzer列表。
springboot提供了一种简单的方法来创建我们自己的自定义FailureAnalyzer。
1
创建自定义FailureAnalyzer
为了创建我们自己的自定义FailureAnalyzer,我们可以使用AbstractFailureAnalyzer作为方便的扩展点,AbstractFailureAnalyzer将检查是否存在指定的异常,并允许我们的自定义分析器处理它。
我们在springboot应用中为下述用例创建一个自定义FailureAnalyze:
- 尝试为给定的依赖注入一个不同的bean
- 当我们尝试注入它时,Spring将抛出BeanNotOfRequiredTypeException异常,因为我们正在尝试注入不同的bean
下面试简单的FailureAnalyzer代码:
public class CustomFailureAnalyzer extends AbstractFailureAnalyzer<BeanNotOfRequiredTypeException> { /** * Returns an analysis of the given {@code failure}, or {@code null} if no analysis * was possible. * * @param rootFailure the root failure passed to the analyzer * @param cause the actual found cause * @return the analysis or {@code null} */ @Override protected FailureAnalysis analyze(Throwable rootFailure, BeanNotOfRequiredTypeException cause) { String message ="####################### This is a custom fail Message ################ %n" getDescription(cause); return new FailureAnalysis(message , (String)null, cause); } private String getDescription(BeanNotOfRequiredTypeException ex) { StringWriter description = new StringWriter(); PrintWriter printer = new PrintWriter(description); printer.printf( "The bean %s could not be injected" "due to %s", ex.getBeanName(), ex.getRequiredType().getName()); return description.toString(); } }
重点在于analyze()方法,它将被触发,springboot将传递一个Throwable对象以及用例(也就是Spring抛出的异常)。
2
注册自定义FailureAnalyzer
我们需要一种特殊的方法来用springboot注册自定义FailureAnalyzer,以便springboot能够在系统引发异常的情况下调用自定义FailureAnalyzer,需要使用META-INF文件夹中的spring.factories属性文件来注册它。
如果META-INF文目录或者spring.factories文件不存在,需要手动创建,若要注册自定义FailureAnalyzer,在spring.factories中添加以下条目:
org.springframework.boot.diagnostics.FailureAnalyzer= com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer
如果有多个FailureAnalyzer,您可以使用逗号分隔将其注册为多个条目:
org.springframework.boot.diagnostics.FailureAnalyzer= com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer, com.umeshawasthi.failureanalyzer.CustomFailureAnalyzer1
到这里,我们设置了所有的自定义FailureAnalyzer并且可以测试了。
3
FailureAnalyzer实际应用
我在示例中创建了2个类,内容如下:
public class AdminDAO { public void helloAdmin(){ System.out.println("Hello Admin"); } } @Repository("adminDAO") public class AdminDAOImpl { public void setupAdmin(){ //default implimentation } }
创建一个控制器,并且将AdminDAO以adminDAO属性注入进去:
@RestController public class HelloWorldController { @Resource(name = "adminDAO") private AdminDAO adminDAO; //some methods }
如果运行springboot应用程序 ,Spring将尝试在AdminDAO中注入AdminDAOImpl类型的adminDao,因为类型不兼容,Spring将抛出BeanNotOfRequiredTypeException,在当前用例中,springboot将检查并确定注册了一个有效的FailureAnalyzer,并将信息传递给注册的FailureAnalyzer。
在我们的例子中,我们已经注册了CustomFailureAnalyzer来处理这种情况,springboot将把这个信息传递给我们的自定义FailureAnalyzer以产生更加友好的消息。
这是我们运行应用程序时的输出:
*************************** APPLICATION FAILED TO START *************************** Description: ################# This is a custom fail Message ################ %nThe bean adminDAO could not be injecteddue to com.umeshawasthi.service.AdminDAO
总结
在本文中,我们探究了springboot提供的一个有趣的特性,我们看到了springboot FailureAnalyzer的工作原理以及如何创建我们自己的自定义FailureAnalyzer。