Spring Boot 应用
本节包含与 Spring Boot 应用直接相关的主题。
创建你自己的 FailureAnalyzer
FailureAnalyzer
是一种在启动时拦截异常并将其转换为易于理解的消息(包含在 FailureAnalysis
中)的好方法。Spring Boot 为应用上下文相关的异常、JSR-303 验证等等提供了这样的分析器。你也可以创建你自己的分析器。
AbstractFailureAnalyzer
是 FailureAnalyzer
的一个便捷扩展,它检查要处理的异常中是否存在指定的异常类型。你可以从中扩展,以便你的实现只有在异常实际存在时才有机会处理它。如果由于任何原因你无法处理异常,请返回 null
,以便其他实现有机会处理该异常。
FailureAnalyzer
实现必须在 META-INF/spring.factories
中注册。以下示例注册了 ProjectConstraintViolationFailureAnalyzer
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要访问BeanFactory 或Environment ,请在您的FailureAnalyzer 实现中将它们声明为构造函数参数。 |
自动配置故障排除
Spring Boot 自动配置尽力做到“正确的事情”,但有时会失败,而且很难知道原因。
在任何 Spring Boot ApplicationContext
中都提供了一个非常有用的ConditionEvaluationReport
。如果启用DEBUG
日志输出,您可以看到它。如果您使用spring-boot-actuator
(参见Actuator部分),还有一个conditions
端点以 JSON 格式呈现报告。使用此端点调试应用程序,并查看 Spring Boot 在运行时添加了哪些功能(以及哪些功能未添加)。
查看源代码和 API 文档可以解答更多问题。阅读代码时,请记住以下经验法则:
-
查找名为
*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
注解。 -
查找
@ConditionalOnExpression
注解,这些注解根据 SpEL 表达式(通常使用从Environment
解析的占位符进行评估)打开和关闭功能。
在应用程序启动之前自定义环境或 ApplicationContext
SpringApplication
具有ApplicationListeners
和ApplicationContextInitializers
,用于对上下文或环境应用自定义设置。Spring Boot 加载许多此类内部使用的自定义设置,这些设置来自META-INF/spring.factories
。注册其他自定义设置的方法不止一种:
-
以编程方式,针对每个应用程序,在运行之前调用
SpringApplication
上的addListeners
和addInitializers
方法。 -
声明性地,对于所有应用程序,通过添加
META-INF/spring.factories
并打包所有应用程序都用作库的 jar 文件。
SpringApplication
向侦听器发送一些特殊的ApplicationEvents
(有些甚至在创建上下文之前),然后注册侦听器以接收ApplicationContext
发布的事件。有关完整列表,请参阅“Spring Boot 功能”部分中的应用程序事件和侦听器。
还可以通过使用EnvironmentPostProcessor
在应用程序上下文刷新之前自定义Environment
。每个实现都应在META-INF/spring.factories
中注册,如下例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
实现可以加载任意文件并将其添加到Environment
。例如,以下示例从类路径加载 YAML 配置文件:
-
Java
-
Kotlin
import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
public class MyEnvironmentPostProcessor 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) {
Assert.isTrue(path.exists(), () -> "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);
}
}
}
import org.springframework.boot.SpringApplication
import org.springframework.boot.env.EnvironmentPostProcessor
import org.springframework.boot.env.YamlPropertySourceLoader
import org.springframework.core.env.ConfigurableEnvironment
import org.springframework.core.env.PropertySource
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.Resource
import org.springframework.util.Assert
import java.io.IOException
class MyEnvironmentPostProcessor : EnvironmentPostProcessor {
private val loader = YamlPropertySourceLoader()
override fun postProcessEnvironment(environment: ConfigurableEnvironment, application: SpringApplication) {
val path: Resource = ClassPathResource("com/example/myapp/config.yml")
val propertySource = loadYaml(path)
environment.propertySources.addLast(propertySource)
}
private fun loadYaml(path: Resource): PropertySource<*> {
Assert.isTrue(path.exists()) { "Resource $path does not exist" }
return try {
loader.load("custom-resource", path)[0]
} catch (ex: IOException) {
throw IllegalStateException("Failed to load yaml configuration from $path", ex)
}
}
}
Environment 已经准备好了 Spring Boot 默认加载的所有常用属性源。因此,可以从环境中获取文件的位置。前面的示例在列表的末尾添加custom-resource 属性源,以便在任何其他常用位置定义的键优先。自定义实现可以定义其他顺序。 |
虽然在您的@SpringBootApplication 上使用@PropertySource 似乎是加载Environment 中自定义资源的便捷方法,但我们不推荐这样做。此类属性源直到应用程序上下文正在刷新时才添加到Environment 中。这对于配置某些属性(如logging.* 和spring.main.* )为时已晚,因为这些属性在刷新开始之前读取。 |
构建 ApplicationContext 层次结构(添加父上下文或根上下文)
您可以使用ApplicationBuilder
类创建父子ApplicationContext
层次结构。有关更多信息,请参阅“Spring Boot 功能”部分中的Fluent Builder API。
创建非 Web 应用程序
并非所有 Spring 应用程序都必须是 Web 应用程序(或 Web 服务)。如果您想在main
方法中执行一些代码,但也要引导 Spring 应用程序来设置要使用的基础结构,则可以使用 Spring Boot 的SpringApplication
功能。SpringApplication
会更改其ApplicationContext
类,具体取决于它是否认为需要 Web 应用程序。您可以做的第一件事是帮助它从类路径中删除服务器相关的依赖项(例如 servlet API)。如果您无法做到这一点(例如,如果您从同一个代码库运行两个应用程序),则可以在您的SpringApplication
实例上显式调用setWebApplicationType(WebApplicationType.NONE)
,或设置applicationContextClass
属性(通过 Java API 或外部属性)。您要作为业务逻辑运行的应用程序代码可以实现为CommandLineRunner
,并作为@Bean
定义放入上下文。