我想实现以下用例-仅在application.yaml中设置了某个属性时,我的spring boot应用程序才应启动:
myapp
active: true
如果未设置该属性,则上下文初始化应失败,并带有一些给定的消息,提示该属性丢失。
我在本主题中找到了实现方法:Spring Boot - Detect and terminate if property not set?,但是为什么我不能遵循这种方法的问题是,在检查该属性的bean加载之前,上下文初始化可能失败
例如,如果由于缺少另一个属性而导致某些其他bean无法加载,则上下文初始化将在此时失败,并且检查所需属性的bean将不会加载。这对我来说不行,因为我希望在加载任何其他bean之前先检查 myapp.active 属性。
之所以想拥有它,是因为在运行应用程序时应设置一个特定的配置文件-application- [profile] .yaml包含“ myapp.active:true”和一些其他必填属性。加载上下文所需。
我希望我的应用程序总是因为myapp.active不是true而失败,因此我可以输出一条有意义的消息,告知该配置文件丢失,并且该应用程序必须使用其中一个配置文件运行(来自给定的配置文件列表) )。一些不是开发人员的人正在运行该应用程序,因此我希望他们知道为什么该应用程序无法运行,否则他们会认为该应用程序中存在一些错误。
我该如何实现?可以在装入bean之前以某种方式读取属性吗?我想避免在所有bean上设置 @DependsOn (或通过BeanPostProcesser进行相同操作),并寻求一种更优雅的解决方案。
答案 0 :(得分:5)
如果您使用财产条件,则该应用程序将无法启动。够快吗?
@SpringBootApplication
@ConditionalOnProperty(name = "myapp.active")
public class FastFailWhenPropertyNotPresentApplication {
public static void main(String[] args) {
SpringApplication.run(FastFailWhenPropertyNotPresentApplication.class, args);
}
}
基本上@SpringBootApplication
只是@Configuration
类。
您有一个选项matchIfMissing
,可用于指定如果未设置该属性,则条件是否应匹配。默认为false。
编辑:
一个更好的解决方案是通过将@ConfigurationProperties
与@Validated
结合使用来配置属性,因此可以使用javax.validation.constraints批注。
package stackoverflow.demo;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@Component
@ConfigurationProperties(prefix = "myapp")
@Validated
public class MyAppProperties {
@AssertTrue
@NotNull
private Boolean active;
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
}
注意:您可以省略@ConditionalOnProperty(name = "myapp.active")
将@AssertTrue
与@NotNull
结合使用是因为@AssertTrue
将空元素视为有效。
和spring-boot免费生成一个不错的错误消息:
***************************
APPLICATION FAILED TO START
***************************
Description:
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'myapp' to stackoverflow.demo.MyAppProperties failed:
Property: myapp.active
Value: false
Origin: class path resource [application.properties]:1:16
Reason: must be true
Action:
Update your application's configuration
编辑(更新问题后)
一种更快的方法:您的应用程序将无法启动,也不会加载应用程序上下文
package stackoverflow.demo;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.ClassPathResource;
@SpringBootApplication
public class FastFailWhenPropertyNotPresentApplication {
static Boolean active;
static {
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("application.yaml"));
active = (Boolean) yaml.getObject().getOrDefault("myapp.active", false);
}
public static void main(String[] args) {
if (!active) {
System.err.println("your fail message");
} else {
SpringApplication.run(FastFailWhenPropertyNotPresentApplication.class, args);
}
}
}
另一种最适合您需求的解决方案...
通过收听ApplicationEnvironmentPreparedEvent
{@ link SpringApplication}启动时发布的事件 * {@link Environment}首先可用于检查和修改。 *
注意:您不能使用@EventListener
,但已将侦听器添加到SpringApplication
package stackoverflow.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
@SpringBootApplication
public class FastFailWhenPropertyNotPresentApplication {
static class EnvironmentPrepared implements ApplicationListener<ApplicationEnvironmentPreparedEvent>{
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
Boolean active = event.getEnvironment().getProperty("myapp.active",Boolean.class,Boolean.FALSE);
if(!active) {
throw new RuntimeException("APPLICATION FAILED TO START: ACTIVE SHOULD BE TRUE ");
}
}
};
public static void main(String[] args) throws Exception {
SpringApplication springApplication = new SpringApplication(FastFailWhenPropertyNotPresentApplication.class);
springApplication.addListeners(new FastFailWhenPropertyNotPresentApplication.EnvironmentPrepared());
springApplication.run(args);
}
}