此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Boot 3.4.3! |
Spring Boot 应用程序
本节包括与 Spring Boot 应用程序直接相关的主题。
创建您自己的 FailureAnalyzer
FailureAnalyzer
是在启动时拦截异常并将其转换为人类可读的消息的好方法,包装在FailureAnalysis
.
Spring Boot 为与应用程序上下文相关的异常、JSR-303 验证等提供了这样的分析器。
您也可以创建自己的。
AbstractFailureAnalyzer
是FailureAnalyzer
,该命令检查要处理的异常中是否存在指定的异常类型。
您可以从该位置进行扩展,以便您的实现仅在实际存在异常时才有机会处理异常。
如果由于某种原因无法处理异常,则返回null
为另一个 implementation 提供处理异常的机会。
FailureAnalyzer
implementations 必须在META-INF/spring.factories
.
以下示例 registersProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
如果您需要访问BeanFactory 或Environment ,在FailureAnalyzer 实现。 |
自动配置疑难解答
Spring Boot 自动配置会尽最大努力“做正确的事情”,但有时事情会失败,而且很难说出原因。
有一个非常有用的ConditionEvaluationReport
在任何 Spring Boot 中可用ApplicationContext
.
如果您启用DEBUG
logging 输出。
如果您使用spring-boot-actuator
(请参阅 Actuator 部分),还有一个conditions
以 JSON 格式呈现报告的终端节点。
使用该端点调试应用程序并查看 Spring Boot 在运行时添加了哪些功能(以及尚未添加哪些功能)。
通过查看源代码和 API 文档,可以回答更多问题。 阅读代码时,请记住以下经验法则:
-
查找名为
*AutoConfiguration
并阅读他们的来源。 请特别注意@Conditional*
annotations 来了解它们启用的功能以及何时启用。 加--debug
添加到命令行或 System 属性-Ddebug
在控制台上获取在您的应用程序中做出的所有自动配置决策的日志。 在启用了 actuator 的正在运行的应用程序中,查看conditions
端点 (/actuator/conditions
或 JMX 等效项)获取相同的信息。 -
查找
@ConfigurationProperties
(例如ServerProperties
),然后从那里读取可用的外部配置选项。 这@ConfigurationProperties
annotation 具有name
属性,该属性充当外部属性的前缀。 因此ServerProperties
具有prefix="server"
,其配置属性为server.port
,server.address
等。 在启用了 actuator 的正在运行的应用程序中,查看configprops
端点。 -
查找
bind
方法上的Binder
要将配置值显式地从Environment
以轻松的方式。 它通常与前缀一起使用。 -
查找
@Value
直接绑定到Environment
. -
查找
@ConditionalOnExpression
为响应 SPEL 表达式而打开和关闭功能的注释,通常使用从Environment
.
在启动之前自定义 Environment 或 ApplicationContext
一个SpringApplication
具有ApplicationListener
和ApplicationContextInitializer
用于将自定义项应用于上下文或环境的实现。
Spring Boot 加载了许多这样的自定义,以便在内部使用META-INF/spring.factories
.
有多种方法可以注册其他自定义项:
-
以编程方式,每个应用程序通过调用
addListeners
和addInitializers
方法SpringApplication
在运行它之前。 -
以声明方式,对于所有应用程序,通过添加
META-INF/spring.factories
以及打包应用程序都用作库的 jar 文件。
这SpringApplication
发送一些特殊的ApplicationEvents
传递给侦听器(有些甚至在创建上下文之前),然后为ApplicationContext
也。
有关完整列表,请参见“ Spring Boot 功能”部分中的 Application Events and Listeners 。
还可以自定义Environment
在使用EnvironmentPostProcessor
.
每个实现都应该在META-INF/spring.factories
,如以下示例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将它们添加到Environment
.
例如,以下示例从 Classpath 加载 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(), () -> "'path' [%s] must exist".formatted(path));
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)
}
}
}
The Environment
has already been prepared with all the usual property sources that Spring Boot loads by default.
It is therefore possible to get the location of the file from the environment.
The preceding example adds the custom-resource
property source at the end of the list so that a key defined in any of the usual other locations takes precedence.
A custom implementation may define another order.
While using @PropertySource
on your @SpringBootApplication
may seem to be a convenient way to load a custom resource in the Environment
, we do not recommend it.
Such property sources are not added to the Environment
until the application context is being refreshed.
This is too late to configure certain properties such as logging.*
and spring.main.*
which are read before refresh begins.
Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)
You can use the SpringApplicationBuilder
class to create parent/child ApplicationContext
hierarchies.
See Fluent Builder API in the “Spring Boot Features” section for more information.
Create a Non-web Application
Not all Spring applications have to be web applications (or web services).
If you want to execute some code in a main
method but also bootstrap a Spring application to set up the infrastructure to use, you can use the SpringApplication
features of Spring Boot.
A SpringApplication
changes its ApplicationContext
class, depending on whether it thinks it needs a web application or not.
The first thing you can do to help it is to leave server-related dependencies (such as the servlet API) off the classpath.
If you cannot do that (for example, if you run two applications from the same code base) then you can explicitly call setWebApplicationType(WebApplicationType.NONE)
on your SpringApplication
instance or set the applicationContextClass
property (through the Java API or with external properties).
Application code that you want to run as your business logic can be implemented as a CommandLineRunner
and dropped into the context as a @Bean
definition.