java – How to conditionally make a Spring Boot application terminate at startup based on a property

java – How to conditionally make a Spring Boot application terminate at startup based on a property

The application wont start if you use a condition-on-property. Fast enough?

 @SpringBootApplication
 @ConditionalOnProperty(name = myapp.active)
 public class FastFailWhenPropertyNotPresentApplication {

     public static void main(String[] args) {
            SpringApplication.run(FastFailWhenPropertyNotPresentApplication.class, args);
    }

}

Basically @SpringBootApplication is just a @Configuration class.

You have an option matchIfMissing that you can use to specify if the condition should match if the property is not set. Defaults to false.

EDIT:

A better solution is to configure your property via a @ConfigurationProperties combined with @Validated, so you can use the javax.validation.constraints annotations.

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

}

note: you can leave out @ConditionalOnProperty(name = myapp.active)

use @AssertTrue in combination with @NotNull because of @AssertTrueconsiders null elements as valid.

and spring-boot generates a nice error-message for free:

***************************
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 applications configuration

EDIT (after updated question)


A faster way: your application wont start, nor an application-context will be loaded

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

}

EDIT

another solution that probably fits your needs best…

By listening to the ApplicationEnvironmentPreparedEvent

Event published when a {@link SpringApplication} is starting up and the
* {@link Environment} is first available for inspection and modification.
*

note: you cannot use a @EventListener, but you have add the Listener to the 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);
  }

}

One option would be to create a bean which checks for the presence of the property, and throw an exception during bean creation if the property is not set.

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

java – How to conditionally make a Spring Boot application terminate at startup based on a property

Leave a Reply

Your email address will not be published. Required fields are marked *