簡體   English   中英

如何根據屬性有條件地使 Spring Boot 應用程序在啟動時終止

[英]How to conditionally make a Spring Boot application terminate at startup based on a property

我想實現以下用例 - 只有在application.yaml中設置了某個屬性時,我的 Spring Boot 應用程序才應該啟動:

myapp:
  active: true

如果未設置該屬性,則上下文初始化應失敗並顯示缺少該屬性的消息。

我在這個主題中找到了如何實現它: Spring Boot - 如果未設置屬性,則檢測並終止? 但我不能遵循這種方法的問題是,在加載檢查此屬性的 bean 之前,上下文初始化可能會失敗。

例如,如果某個其他 bean 由於缺少另一個屬性而無法加載,則上下文初始化將在此時失敗,並且我的用於檢查所需屬性的 bean 將不會被加載。 這對我來說myapp.active因為我希望在加載任何其他 bean 之前首先檢查myapp.active屬性。

我想要這樣的原因是在運行應用程序時應該設置某個配置文件 - application-[profile].yaml包含myapp.active: true和加載上下文所需的其他一些強制性屬性.

我希望我的應用程序總是失敗,因為 myapp.active 不是真的,這樣我就可以輸出一條有意義的消息,告訴配置文件丟失,並且應用程序必須使用其中一個配置文件(來自給定的配置文件列表)運行。 一些不是開發人員的人正在運行該應用程序,所以我希望他們知道該應用程序沒有運行的原因,否則他們會認為該應用程序中存在一些錯誤。

我怎樣才能做到這一點? 是否有可能在加載 bean 之前以某種方式讀取屬性? 我想避免在所有 bean 上設置@DependsOn (或通過BeanPostProcesser做同樣的事情)並且正在尋找更優雅的解決方案。

如果您使用財產條件,則該應用程序將無法啟動。 夠快嗎?

 @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);
  }

}

一種選擇是創建一個 bean 來檢查屬性是否存在,如果未設置屬性,則在 bean 創建期間拋出異常。

@Component
public static EnsureApplicationActive {
    @Value("${myapp.active}")
    private Boolean active;

    @PostConstruct
    public void ensureApplicationActive() {
        if (!Boolean.TRUE.equals(active)) {
            throw new IllegalStateException("TODO: Meaningful message goes here");
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM