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