On this page
76. Spring Boot 应用程序
本部分包括与 Spring Boot 应用程序直接相关的主题。
76.1 创建自己的 FailureAnalyzer
FailureAnalyzer是一种很好的拦截启动时异常并将其转换为人类可读的消息的方法,并封装在FailureAnalysis中。 Spring Boot 为与应用程序上下文相关的异常,JSR-303 验证等提供了此类分析器。您也可以创建自己的。
AbstractFailureAnalyzer
是FailureAnalyzer
的便捷扩展,它检查要处理的异常中是否存在指定的异常类型。您可以对此进行扩展,以便您的实现只有在实际存在异常时才有机会处理该异常。如果由于某种原因无法处理该异常,请返回null
,以使另一个实现有机会处理该异常。
FailureAnalyzer
实现必须在META-INF/spring.factories
中注册。以下示例注册ProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
Note
如果您需要访问BeanFactory
或Environment
,则您的FailureAnalyzer
可以分别简单地实现BeanFactoryAware
或EnvironmentAware
。
76.2 自动配置故障排除
Spring Boot 自动配置会尽力“做正确的事”,但是有时候事情会失败,而且很难说出原因。
Spring Boot ApplicationContext
中有一个非常有用的ConditionEvaluationReport
。如果启用DEBUG
日志记录输出,则可以看到它。如果您使用spring-boot-actuator
(请参见Actuator 章节),则还有一个conditions
端点以 JSON 渲染报告。使用该端点来调试应用程序,并在运行时查看 Spring Boot 添加了哪些功能(哪些尚未添加)。
通过查看源代码和 Javadoc,可以回答更多问题。阅读代码时,请记住以下经验法则:
查找名为
*AutoConfiguration
的类,并阅读其源代码。请特别注意@Conditional*
注解,以了解它们启用了哪些功能以及何时启用。将--debug
添加到命令行或系统属性-Ddebug
,以在控制台上获取在您的应用中做出的所有自动配置决策的日志。在正在运行的 Actuator 应用程序中,查看conditions
端点(/actuator/conditions
或等效的 JMX)以获取相同的信息。查找
@ConfigurationProperties
的类(例如ServerProperties),然后从中读取可用的外部配置选项。@ConfigurationProperties
注解具有name
属性,该属性充当外部属性的前缀。因此,ServerProperties
具有prefix="server"
,并且其配置属性是server.port
,server.address
等。在正在运行的 Actuator 应用程序中,查看configprops
端点。寻找在
Binder
上使用bind
方法以轻松地将配置值从Environment
中拉出的用法。它通常与前缀一起使用。查找直接绑定到
Environment
的@Value
Comments。寻找
@ConditionalOnExpression
Comments,这些 Comments 可根据 SpEL 表达式打开和关闭功能,这些 Comments 通常使用从Environment
解析的占位符进行评估。
76.3 在启动环境或 ApplicationContext 之前对其进行自定义
SpringApplication
具有ApplicationListeners
和ApplicationContextInitializers
,用于将自定义项应用于上下文或环境。 Spring Boot 从META-INF/spring.factories
内部加载了许多此类自定义内容供内部使用。注册其他自定义项的方法有多种:
在运行每个应用程序之前,通过在
SpringApplication
上调用addListeners
和addInitializers
方法,以编程方式进行操作。通过设置
context.initializer.classes
或context.listener.classes
属性,以声明方式针对每个应用程序。声明性地,对于所有应用程序,通过添加一个
META-INF/spring.factories
并将一个 jar 文件打包为应用程序全部用作库。
SpringApplication
向侦听器发送一些特殊的ApplicationEvents
(某些情况甚至在创建上下文之前),然后为ApplicationContext
发布的事件注册侦听器。有关完整列表,请参见“ Spring Boot 功能”部分中的“ 第 23.5 节“应用程序事件和侦听器””。
也可以在使用EnvironmentPostProcessor
刷新应用程序上下文之前自定义Environment
。每个实现都应在META-INF/spring.factories
中注册,如以下示例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将其添加到Environment
。例如,以下示例从 Classpath 加载 YAML 配置文件:
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).get(0);
}
catch (IOException ex) {
throw new IllegalStateException(
"Failed to load yaml configuration from " + path, ex);
}
}
}
Tip
Environment
已经准备好了 Spring Boot 默认加载的所有常用属性源。因此,可以从环境中获取文件的位置。前面的示例将custom-resource
属性源添加到列表的末尾,以便在其他任何常见位置定义的键都具有优先权。定制实现可以定义另一个 Sequences。
Warning
虽然在@SpringBootApplication
上使用@PropertySource
似乎是在Environment
中加载自定义资源的便捷方法,但我们不建议您这样做,因为 Spring Boot 在刷新ApplicationContext
之前会准备Environment
。用@PropertySource
定义的任何键加载得太晚,以至于对自动配置没有任何影响。
76.4 构建 ApplicationContext 层次结构(添加父上下文或根上下文)
您可以使用ApplicationBuilder
类创建父/子ApplicationContext
层次结构。有关更多信息,请参见“ Spring Boot 功能”部分中的“ 第 23.4 节“ Fluent Builder API””。
76.5 创建非 Web 应用程序
并非所有的 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。如果要用main
方法执行一些代码,又要引导 Spring 应用程序来设置要使用的基础架构,则可以使用 Spring Boot 的SpringApplication
功能。 SpringApplication
更改其ApplicationContext
类,具体取决于它是否认为需要 Web 应用程序。您可以做的第一件事是将与服务器相关的依存关系(例如 Servlet API)从 Classpath 中移开。如果您不能执行此操作(例如,从同一代码库运行两个应用程序),则可以在SpringApplication
实例上显式调用setWebApplicationType(WebApplicationType.NONE)
或设置applicationContextClass
属性(通过 Java API 或带有外部属性)。您可以将要作为业务逻辑运行的应用程序代码实现为CommandLineRunner
,并可以将其作为@Bean
定义放到上下文中。