spring-boot/docs/howto.md
2013-11-26 18:00:50 +00:00

8.8 KiB

How Do I Do That With Spring Boot?

Here is a starting point for a potentially large collection of micro HOWTO guides. If you want to add a placeholder for a question without an answer, put it at the top (at header level 2) and we can fill in the gaps later.

Configure Tomcat

Configure Jetty

Test a Spring Boot Application

A Spring Boot application is just a Spring ApplicationContext so nothing very special has to be done to test it beyond what you would normally do with a vanilla Spring context. One thing to watch out for though is that the external properties, logging and other features of Spring Boot are only installed in the context by default if you use SpringApplication to create it. Spring Boot has a special Spring TestContextLoader which makes this job easy. For example (from the JPA Sample):

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SampleDataJpaApplication.class, 
        loader = SpringApplicationContextLoader.class)
public class CityRepositoryIntegrationTests {

	@Autowired
	CityRepository repository;

...

To use the SpringApplicationContextLoader you need the test jar on your classpath (recommended Maven co-ordinates "org.springframework.boot:spring-boot-starter-test"). The context loader guesses whether you want to test a web application or not (e.g. with MockMVC) by looking for the @WebAppConfiguration annotation (MockMVC and @WebAppConfiguration are from the Spring Test support library).

## Externalize the Configuration of SpringApplication

A SpringApplication has bean properties (mainly setters) so you can use its Java API as you create the application to modify its behaviour. Or you can externalize the configuration using properties in spring.main.*. E.g. in application.properties you might have

spring.main.web_environment: false
spring.main.show_banner: false

and then the Spring Boot banner will not be printed on startup, and the application will not be a web application.

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 web depdendencies 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.

Create a Deployable WAR File

Use the SpringBootServletInitializer base class, which is picked up by Spring's Servlet 3.0 support on deployment. Add an extension of that to your project and build a WAR file as normal. For more detail, see the "Converting a JAR Project to a WAR" guide on the spring.io website.

The WAR file can also be executable if you use the Spring Boot build tools. In that case the embedded container classes (to launch Tomcat for instance) have to be added to the WAR in a lib-provided directory. The tools will take care of that as long as the dependencies are marked as "provided" in Maven or Gradle. Here's a Maven example in the Boot Samples.

Create a Deployable WAR File for older Servlet Containers

Older Servlet containers don't have support for the ServletContextInitializer bootstrap process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers but you are going to need to add a web.xml to your application and configure it to load an ApplicationContext via a DispatcherServlet.

TODO: add some detail.

Discover Built-in Options for External Properties

Spring Boot binds external properties from application.properties (or .yml) (and other places) into an application at runtime. There is not (and technically cannot be) an exhaustive list of all supported properties in a single location because contributions can come from additional JAR files on your classpath. There is a sample application.yml with a non-exhaustive and possibly inaccurate list of properties supported by Spring Boot vanilla with autoconfiguration. The definitive list comes from searching the source code for @ConfigurationProperties and @Value annotations, as well as the occasional use of RelaxedEnvironment (c.f. here).

Set the Active Spring Profiles

The Spring Environment has an API for this, but normally you would set a System profile (spring.profiles.active) or an OS environment variable (SPRING_PROFILES_ACTIVE). E.g. launch your application with a -D... argument (remember to put it before the main class or jar archive):

java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar

In Spring Boot you can also set the active profile in application.properties, e.g.

spring.profiles.active: production

A value set this is replaced by the System property or environment variable setting, but not by the SpringApplicationBuilder.profiles() method. Thus the latter Java API can be used to augment the profiles without changing the defaults.

Change the Location of External Properties of an Application

Properties from different sources are added to the Spring Environment in a defined order, and the precedence for resolution is

  1. commandline, 2) filesystem (current working directory) application.properties, 3) classpath application.properties. To modify this you can provide System properties (or environment variables)
  • config.name (CONFIG_NAME), defaults to application as the root of the file name
  • config.location (CONFIG_LOCATION) is a comma-separated list of files to load. A separate Environment property source is set up for each document found, so the priority order is most significant first. Defaults to file:./application.properties,classpath:application.properties. If YAML is used then those files are also added to the list by default.

See ConfigFileApplicationContextInitializer for more detail.

Use YAML for External Properties

YAML is a superset of JSON and as such is a very convenient syntax for storing external properties in a hierarchical format. E.g.

spring:
  application:
    name: cruncher
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost/test
server:
  port: 9000

Create a file called application.yml and stick it in the root of your classpath, and also add snake-yaml to your classpath (Maven co-ordinates org.yaml:snake-yaml). A YAML file is parsed to a Java Map<String,Object> (like a JSON object), and Spring Boot flattens the maps so that it is 1-level deep and has period-separated keys, a lot like people are used to with Properties files in Java.

The example YAML above corresponds to an application.properties file

spring.application.name: cruncher
spring.datasource.driverClassName: com.mysql.jdbc.Driver
spring.datasource.url: jdbc:mysql://localhost/test
server.port: 9000

Change Configuration Depending on the Environment

A YAML file is actually a sequence of documents separated by --- lines, and each document is parsed separately to a flattened map.

If a YAML document contains a spring.profiles key, then the profiles value (comma-separated list of profiles) is fed into the Spring Environment.acceptsProfiles() and if any of those profiles is active that document is included in the final merge (otherwise not).

Example:

server:
  port: 9000

---

spring:
  profiles: development
server:
  port: 9001

---

spring:
  profiles: production
server:
  port: 0

In this example the default port is 9000, but if the Spring profile "development" is active then the port is 9001, and if "production" is active then it is 0.

The YAML documents are merged in the order they are encountered (so later values override earlier ones).

To do the same thing with properties files you can use application-${profile}.properties to specify profile-specific values.