9.1 Spring Boot应用
本节包括与Spring Boot应用程序直接相关的主题。
9.1.1 创建自己的失败解析器
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可以分别简单地实现BeanFactoryAware或EnvironmentAware。
9.1.2 自动配置疑难解答
Spring Boot自动配置尽力“做正确的事”,但有时事情会失败,而且很难说清楚原因。
9.1.3 在开始之前自定义Environment或ApplicationContext
任何Spring Boot ApplicationContext都有一个非常有用的ConditionEvaluationReport。 如果启用DEBUG日志记录输出,则可以看到它。 如果使用spring-boot-actuator(参见Actuator章节),还有一个条件端点以JSON格式呈现报表。 使用该端点调试应用程序,并查看Spring Boot在运行时添加了哪些功能(以及哪些尚未添加)。
通过查看源代码和Javadoc可以回答更多问题。 阅读代码时,请记住以下经验法则:
- 查找名为AutoConfiguration的类并阅读其来源。 特别注意@Conditional注释,找出它们启用的功能和时间。 将--debug添加到命令行或系统属性-Ddebug,以在控制台上记录应用程序中所做的所有自动配置决策。 在正在运行的Actuator应用程序中,查看条件端点(/actuator/conditions或JMX等效物)以获取相同的信息。
- 查找@ConfigurationProperties(例如ServerProperties)的类,并从那里读取可用的外部配置选项。 @ConfigurationProperties批注具有name属性,该属性充当外部属性的前缀。 因此,ServerProperties具有prefix ="server",其配置属性为server.port,server.address等。 在正在运行的Actuator应用程序中,查看configprops端点。
- 查看Binder上bind方法的使用,以轻松的方式将配置值明确地提取出Environment。 它通常与前缀一起使用。
- 查找直接绑定到Environment的@Value注释。
- 查找@ConditionalOnExpression注释,以响应SpEL表达式打开和关闭功能,通常使用从环境中解析的占位符进行评估。
9.1.4 构建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向侦听器发送一些特殊的ApplicationEvent(有些甚至在创建上下文之前),然后为ApplicationContext发布的事件注册侦听器。 有关完整列表,请参见“Spring Boot功能”部分中的“第4.1.5节”“应用程序事件和监听器”。
在使用EnvironmentPostProcessor刷新应用程序上下文之前,还可以自定义环境。 每个实现都应该在META-INF/spring.factories中注册,如以下示例所示:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
该实现可以加载任意文件并将它们添加到环境中。 例如,以下示例从类路径加载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);
}
}
}
环境已经准备好了Spring Boot默认加载的所有常用属性源。 因此,可以从环境中获取文件的位置。 前面的示例在列表的末尾添加了custom-resource属性source,以便在任何通常的其他位置中定义的键优先。 自定义实现可以定义另一个顺序。
虽然在@SpringBootApplication上使用@PropertySource似乎是在环境中加载自定义资源的一种方便而简单的方法,但我们不建议这样做,因为Spring Boot会在刷新ApplicationContext之前准备环境。 使用@PropertySource定义的任何键加载太晚都不会对自动配置产生任何影响。
9.1.5 创建非Web应用程序
并非所有Spring应用程序都必须是Web应用程序(或Web服务)。 如果要在main方法中执行某些代码,还要引导Spring应用程序来设置要使用的基础结构,则可以使用Spring Boot的SpringApplication功能。 SpringApplication更改其ApplicationContext类,具体取决于它是否认为它需要Web应用程序。 您可以做的第一件事就是将与服务器相关的依赖项(例如servlet API)从类路径中删除。 如果您不能这样做(例如,您从相同的代码库运行两个应用程序),那么您可以在SpringApplication实例上显式调用setWebApplicationType(WebApplicationType.NONE)或设置applicationContextClass属性(通过Java API或外部属性)。 您希望作为业务逻辑运行的应用程序代码可以作为CommandLineRunner实现,并作为@Bean定义放入上下文中。