如何有条件地运行Spring Boot应用程序

时间:2019-05-15 14:58:38

标签: java spring spring-boot

我想实现以下用例-仅在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进行相同操作),并寻求一种更优雅的解决方案。

1 个答案:

答案 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);
  }

}