Spring Boot application
Create your own FailureAnalyzer
FailureAnalyzer
is a great way
to intercept an exception on startup and turn it into a human-readable message, wrapped
into a FailureAnalysis
. Spring
Boot provides such analyzer for application context related exceptions, JSR-303
validations and more. It is actually very easy to create your own.
AbstractFailureAnalyzer
is a convenient extension of FailureAnalyzer
that checks the
presence of a specified exception type in the exception to handle. You can extend from
that so that your implementation gets a chance to handle the exception only when it is
actually present. If for whatever reason you can’t handle the exception, return null
to give another implementation a chance to handle the exception.
FailureAnalyzer
implementations are to be registered in a META-INF/spring.factories
:
the following registers ProjectConstraintViolationFailureAnalyzer
:
org.springframework.boot.diagnostics.FailureAnalyzer=\
com.example.ProjectConstraintViolationFailureAnalyzer
Troubleshoot auto-configuration
The Spring Boot auto-configuration tries its best to ‘do the right thing’, but sometimes things fail and it can be hard to tell why.
There is a really useful ConditionEvaluationReport
available in any Spring Boot
ApplicationContext
. You will see it if you enable DEBUG
logging output. If you use
the spring-boot-actuator
there is also an autoconfig
endpoint that renders the report
in JSON. Use that to debug the application and see what features have been added (and
which not) by Spring Boot at runtime.
Many more questions can be answered by looking at the source code and the Javadoc. Some rules of thumb:
-
Look for classes called
*AutoConfiguration
and read their sources, in particular the@Conditional*
annotations to find out what features they enable and when. Add--debug
to the command line or a System property-Ddebug
to get a log on the console of all the auto-configuration decisions that were made in your app. In a running Actuator app look at theautoconfig
endpoint (‘/autoconfig’ or the JMX equivalent) for the same information. -
Look for classes that are
@ConfigurationProperties
(e.g.ServerProperties
) and read from there the available external configuration options. The@ConfigurationProperties
has aname
attribute which acts as a prefix to external properties, thusServerProperties
hasprefix="server"
and its configuration properties areserver.port
,server.address
etc. In a running Actuator app look at theconfigprops
endpoint. -
Look for use of
RelaxedPropertyResolver
to pull configuration values explicitly out of theEnvironment
. It often is used with a prefix. -
Look for
@Value
annotations that bind directly to theEnvironment
. This is less flexible than theRelaxedPropertyResolver
approach, but does allow some relaxed binding, specifically for OS environment variables (soCAPITALS_AND_UNDERSCORES
are synonyms forperiod.separated
). -
Look for
@ConditionalOnExpression
annotations that switch features on and off in response to SpEL expressions, normally evaluated with placeholders resolved from theEnvironment
.
Customize the Environment or ApplicationContext before it starts
A SpringApplication
has ApplicationListeners
and ApplicationContextInitializers
that
are used to apply customizations to the context or environment. Spring Boot loads a number
of such customizations for use internally from META-INF/spring.factories
. There is more
than one way to register additional ones:
-
Programmatically per application by calling the
addListeners
andaddInitializers
methods onSpringApplication
before you run it. -
Declaratively per application by setting
context.initializer.classes
orcontext.listener.classes
. -
Declaratively for all applications by adding a
META-INF/spring.factories
and packaging a jar file that the applications all use as a library.
The SpringApplication
sends some special ApplicationEvents
to the listeners (even
some before the context is created), and then registers the listeners for events published
by the ApplicationContext
as well. See
boot-features-application-events-and-listeners in the
‘Spring Boot features’ section for a complete list.
It is also possible to customize the Environment
before the application context is
refreshed using EnvironmentPostProcessor
. Each implementation should be registered in
META-INF/spring.factories
:
org.springframework.boot.env.EnvironmentPostProcessor=com.example.YourEnvironmentPostProcessor
The implementation can load arbitrary files and add them to the Environment
. For
instance, this example loads a YAML configuration file from the classpath:
public class EnvironmentPostProcessorExample implements EnvironmentPostProcessor {
private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
Resource path = new ClassPathResource("com/example/myapp/config.yml");
PropertySource<?> propertySource = loadYaml(path);
environment.getPropertySources().addLast(propertySource);
}
private PropertySource<?> loadYaml(Resource path) {
if (!path.exists()) {
throw new IllegalArgumentException("Resource " + path + " does not exist");
}
try {
return this.loader.load("custom-resource", path, null);
}
catch (IOException ex) {
throw new IllegalStateException(
"Failed to load yaml configuration from " + path, ex);
}
}
}
The Environment will already have been prepared with all the usual property sources
that Spring Boot loads by default. It is therefore possible to get the location of the
file from the environment. This example adds the custom-resource property source at the
end of the list so that a key defined in any of the usual other locations takes
precedence. A custom implementation may obviously defines another order.
|
While using @PropertySource on your @SpringBootApplication seems convenient and
easy enough to load a custom resource in the Environment , we do not recommend it as
Spring Boot prepares the Environment before the ApplicationContext is refreshed. Any
key defined via @PropertySource will be loaded too late to have any effect on
auto-configuration.
|
Build an ApplicationContext hierarchy (adding a parent or root context)
You can use the ApplicationBuilder
class to create parent/child ApplicationContext
hierarchies. See boot-features-fluent-builder-api
in the ‘Spring Boot features’ section for more information.
Create a non-web application
Not all Spring applications have to be web applications (or web services). If you want to
execute some code in a main
method, but also bootstrap a Spring application to set up
the infrastructure to use, then it’s easy with the SpringApplication
features of Spring
Boot. A SpringApplication
changes its ApplicationContext
class depending on whether it
thinks it needs a web application or not. The first thing you can do to help it is to just
leave the servlet API dependencies off the classpath. If you can’t do that (e.g. you are
running 2 applications from the same code base) then you can explicitly call
setWebEnvironment(false)
on your SpringApplication
instance, or set the
applicationContextClass
property (through the Java API or with external properties).
Application code that you want to run as your business logic can be implemented as a
CommandLineRunner
and dropped into the context as a @Bean
definition.