62. Spring Boot application

62.1 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 autoconfiguration decisions that were made in your app. In a running Actuator app look at the autoconfig 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 a name attribute which acts as a prefix to external properties, thus ServerProperties has prefix="server" and its configuration properties are server.port, server.address etc. In a running Actuator app look at the configprops endpoint.
  • Look for use of RelaxedEnvironment to pull configuration values explicitly out of the Environment. It often is used with a prefix.
  • Look for @Value annotations that bind directly to the Environment. This is less flexible than the RelaxedEnvironment approach, but does allow some relaxed binding, specifically for OS environment variables (so CAPITALS_AND_UNDERSCORES are synonyms for period.separated).
  • Look for @ConditionalOnExpression annotations that switch features on and off in response to SpEL expressions, normally evaluated with place-holders resolved from the Environment.

62.2 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 and addInitializers methods on SpringApplication before you run it.
  • Declaratively per application by setting context.initializer.classes or context.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 Section 22.4, “Application events and listeners” in the ‘Spring Boot features’ section for a complete list.

62.3 Build an ApplicationContext hierarchy (adding a parent or root context)

You can use the ApplicationBuilder class to create parent/child ApplicationContext hierarchies. See Section 22.3, “Fluent builder API” in the ‘Spring Boot features’ section for more information.

62.4 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 SpringApplication.setWebEnvironment(false), 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.