Spring Boot features-IV
Spring Boot features-IV
23. SpringApplication
The SpringApplication class provides a convenient way to bootstrap a
Spring application that is started from a main() method. In many situations,
you can delegate to the static SpringApplication.run method, as shown in
the following example:
When your application starts, you should see something similar to the
following output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: v2.1.4.RELEASE
***************************
APPLICATION FAILED TO START
***************************
Description:
Embedded servlet container failed to start. Port 8080 was already in use.
Action:
Identify and stop the process that's listening on port 8080 or configure
this application to listen on another port.
If no failure analyzers are able to handle the exception, you can still display
the full conditions report to better understand what went wrong. To do so, you
need to enable
the debug property or enable DEBUG logging for org.springframework.boot.au
toconfigure.logging.ConditionEvaluationReportLoggingListener .
For instance, if you are running your application by using java -jar , you can
enable the debug property as follows:
Inside your banner.txt file, you can use any of the following placeholders:
Description
YAML maps off to false, so be sure to add quotes if you want to disable the
banner in your application, as shown in the following example:
spring:
main:
banner-mode: "off"
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.bannerMode(Banner.Mode.OFF)
.run(args);
Application events are sent in the following order, as your application runs:
1. An ApplicationStartingEvent is sent at the start of a run but before
any processing, except for the registration of listeners and initializers.
2. An ApplicationEnvironmentPreparedEvent is sent when
the Environment to be used in the context is known but before the
context is created.
3. An ApplicationPreparedEvent is sent just before the refresh is started
but after bean definitions have been loaded.
4. An ApplicationStartedEvent is sent after the context has been
refreshed but before any application and command-line runners have
been called.
5. An ApplicationReadyEvent is sent after any application and command-
line runners have been called. It indicates that the application is ready to
service requests.
6. An ApplicationFailedEvent is sent if there is an exception on startup.
You often need not use application events, but it can be handy to know that they
exist. Internally, Spring Boot uses events to handle a variety of tasks.
This means that if you are using Spring MVC and the new WebClient from
Spring WebFlux in the same application, Spring MVC will be used by default.
You can override that easily by
calling setWebApplicationType(WebApplicationType) .
It is often desirable to
call setWebApplicationType(WebApplicationType.NONE) when
using SpringApplication within a JUnit test.
import org.springframework.boot.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
@Component
public class MyBean {
@Autowired
public MyBean(ApplicationArguments args) {
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
// if run with "--debug logfile.txt" debug=true,
files=["logfile.txt"]
}
}
import org.springframework.boot.*;
import org.springframework.stereotype.*;
@Component
public class MyBean implements CommandLineRunner {
@SpringBootApplication
public class ExitCodeApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return () -> 42;
}
.exit(SpringApplication.run(ExitCodeApplication.class, args)));
}
import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;
@Component
public class MyBean {
@Value("${name}")
private String name;
// ...
On your application classpath (for example, inside your jar) you can have
an application.properties file that provides a sensible default property value
for name . When running in a new environment,
an application.properties file can be provided outside of your jar that
overrides the name . For one-off testing, you can launch with a specific
command line switch (for example, java -jar app.jar --name="Spring" ).
my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}
1. file:./config/
2. file:./
3. classpath:/config/
4. classpath:/
1. file:./custom-config/
2. classpath:custom-config/
1. file:./custom-config/
2. classpath:custom-config/
3. file:./config/
4. file:./
5. classpath:/config/
6. classpath:/
This search ordering lets you specify default values in one configuration file
and then selectively override those values in another. You can provide default
values for your application in application.properties (or whatever other
basename you choose with spring.config.name ) in one of the default
locations. These default values can then be overridden at runtime with a
different file located in one of the custom locations.
If you use environment variables rather than system properties, most operating
systems disallow period-separated key names, but you can use underscores instead
(for example, SPRING_CONFIG_NAME instead of spring.config.name).
app.name=MyApp
app.description=${app.name} is a Spring Boot application
You can also use this technique to create “short” variants of existing Spring Boot
properties. See the Section 77.4, “Use ‘Short’ Command Line Arguments”how-to
for details.
environments:
dev:
url: https://dev.example.com
name: Developer Setup
prod:
url: https://another.example.com
name: My Cool App
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
YAML lists are represented as property keys with [index] dereferencers. For
example, consider the following YAML:
my:
servers:
- dev.example.com
- another.example.com
my.servers[0]=dev.example.com
my.servers[1]=another.example.com
To bind to properties like that by using Spring Boot’s Binder utilities (which is
what @ConfigurationProperties does), you need to have a property in the
target bean of type java.util.List (or Set ) and you either need to provide a
setter or initialize it with a mutable value. For example, the following example
binds to the properties shown previously:
@ConfigurationProperties(prefix="my")
public class Config {
server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production & eu-central
server:
address: 192.168.1.120
server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
server:
port: 8000
spring:
security:
user:
password: weak
server:
port: 8000
---
spring:
profiles: !test
security:
user:
password: weak
In the example above, profile negation and profile expressions will not behave
as expected. We recommend that you don’t combine profile-specific YAML
files and multiple YAML documents and stick to using only one of them.
package com.example;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import
org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("acme")
public class AcmeProperties {
}
}
Getters and setters are usually mandatory, since binding is through standard Java
Beans property descriptors, just like in Spring MVC. A setter may be omitted in the
following cases:
Maps, as long as they are initialized, need a getter but not necessarily a setter, since they
can be mutated by the binder.
Collections and arrays can be accessed either through an index (typically with YAML) or by
using a single comma-separated value (properties). In the latter case, a setter is
mandatory. We recommend to always add a setter for such types. If you initialize a
collection, make sure it is not immutable (as in the preceding example).
If nested POJO properties are initialized (like the Security field in the preceding
example), a setter is not required. If you want the binder to create the instance on the fly
by using its default constructor, you need a setter.
Some people use Project Lombok to add getters and setters automatically. Make
sure that Lombok does not generate any particular constructor for such a type, as it
is used automatically by the container to instantiate the object.
Finally, only standard Java Bean properties are considered and binding on static
properties is not supported.
@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
When the @ConfigurationProperties bean is registered that way, the bean has
a conventional name: <prefix>-<fqn>, where <prefix> is the environment key
prefix specified in the @ConfigurationProperties annotation and <fqn> is the
fully qualified name of the bean. If the annotation does not provide any prefix, only
the fully qualified name of the bean is used.
The bean name in the example above is acme-com.example.AcmeProperties.
@Component
@ConfigurationProperties(prefix="acme")
public class AcmeProperties {
# application.yml
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
@Service
public class MyService {
@Autowired
public MyService(AcmeProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new
Server(this.properties.getRemoteAddress());
// ...
}
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
@ConfigurationProperties(prefix="acme.my-project.person")
public class OwnerProperties {
In the preceding example, the following properties names can all be used:
Table 24.1. relaxed binding
Note
erson.first-name Kebab case, which is recommended for use in .properties and .yml files.
erson.first_name Underscore notation, which is an alternative format for use in .properties and .yml file
RSON_FIRSTNAME Upper case format, which is recommended when using system environment variables.
The prefix value for the annotation must be in kebab case (lowercase and
separated by -, such as acme.my-project.person).
amel case, kebab case, or underscore notation Standard list syntax using [ ] or comma-separated v
amel case, kebab case, or underscore notation Standard YAML list syntax or comma-separated valu
pper case format with underscore as the delimiter. _ should not be used Numeric values surrounded by underscores, such as M
thin a property name my.acme[1].other
amel case, kebab case, or underscore notation Standard list syntax using [ ] or comma-separated v
When binding to Map properties, if the key contains anything other than
lowercase alpha-numeric characters or - , you need to use the bracket
notation so that the original value is preserved. If the key is not surrounded
by [] , any characters that are not alpha-numeric or - are removed. For
example, consider binding the following properties to a Map :
acme:
map:
"[/key1]": value1
"[/key2]": value2
/key3: value3
The properties above will bind to a Map with /key1 , /key2 and key3 as the
keys in the map.
For example, assume a MyPojo object with name and description attributes
that are null by default. The following example exposes a list
of MyPojo objects from AcmeProperties :
@ConfigurationProperties("acme")
public class AcmeProperties {
acme:
list:
- name: my name
description: my description
---
spring:
profiles: dev
acme:
list:
- name: my another name
When a List is specified in multiple profiles, the one with the highest priority
(and only that one) is used. Consider the following example:
acme:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
acme:
list:
- name: my another name
In the preceding example, if the dev profile is
active, AcmeProperties.list contains one MyPojo entry (with a name of my
another name and a description of null ). For YAML, both comma-separated
lists and YAML lists can be used for completely overriding the contents of the
list.
For Map properties, you can bind with property values drawn from multiple
sources. However, for the same property in multiple sources, the one with the
highest priority is used. The following example exposes a Map<String,
MyPojo> from AcmeProperties :
@ConfigurationProperties("acme")
public class AcmeProperties {
acme:
map:
key1:
name: my name 1
description: my description 1
---
spring:
profiles: dev
acme:
map:
key1:
name: dev name 1
key2:
name: dev name 2
description: dev description 2
If the dev profile is not active, AcmeProperties.map contains one entry with
key key1 (with a name of my name 1 and a description of my description 1 ).
If the dev profile is enabled, however, map contains two entries with
keys key1 (with a name of dev name 1 and a description of my description
1 ) and key2 (with a name of dev name 2 and a description of dev
description 2 ).
The preceding merging rules apply to properties from all property sources and not
just YAML files.
24.8.4 Properties Conversion
Spring Boot attempts to coerce the external application properties to the right
type when it binds to the @ConfigurationProperties beans. If you need
custom type conversion, you can provide a ConversionService bean (with a
bean named conversionService ) or custom property editors (through
a CustomEditorConfigurer bean) or custom Converters (with bean definitions
annotated as @ConfigurationPropertiesBinding ).
As this bean is requested very early during the application lifecycle, make sure to
limit the dependencies that your ConversionService is using. Typically, any
dependency that you require may not be fully initialized at creation time. You may
want to rename your custom ConversionService if it is not required for
configuration keys coercion and only rely on custom converters qualified
with @ConfigurationPropertiesBinding.
Converting durations
Spring Boot has dedicated support for expressing durations. If you expose
a java.time.Duration property, the following formats in application properties
are available:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
You can also use any of the supported units. These are:
ns for nanoseconds
us for microseconds
ms for milliseconds
s for seconds
m for minutes
h for hours
d for days
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
You can also use any of the supported units. These are:
B for bytes
KB for kilobytes
MB for megabytes
GB for gigabytes
TB for terabytes
If you are upgrading from a previous version that is simply using Long to express
the size, make sure to define the unit (using @DataSizeUnit) if it isn’t bytes
alongside the switch to DataSize. Doing so gives a transparent upgrade path while
supporting a much richer format.
24.8.5 @ConfigurationProperties Validation
Spring Boot attempts to validate @ConfigurationProperties classes
whenever they are annotated with Spring’s @Validated annotation. You can
use JSR-303 javax.validation constraint annotations directly on your
configuration class. To do so, ensure that a compliant JSR-303
implementation is on your classpath and then add constraint annotations to
your fields, as shown in the following example:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
}
You can also trigger validation by annotating the @Bean method that creates the
configuration properties with @Validated.
Although nested properties will also be validated when bound, it’s good
practice to also annotate the associated field as @Valid . This ensure that
validation is triggered even if no nested properties are found. The following
example builds on the preceding AcmeProperties example:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
@NotEmpty
public String username;
You can also add a custom Spring Validator by creating a bean definition
called configurationPropertiesValidator . The @Bean method should be
declared static . The configuration properties validator is created very early in
the application’s lifecycle, and declaring the @Bean method as static lets the
bean be created without having to instantiate the @Configuration class. Doing
so avoids any problems that may be caused by early instantiation. There is
a property validation samplethat shows how to set things up.
The spring-boot-actuator module includes an endpoint that exposes
all @ConfigurationProperties beans. Point your web browser
to/actuator/configprops or use the equivalent JMX endpoint. See the
"Production ready features" section for details.
24.8.6 @ConfigurationProperties vs. @Value
The @Value annotation is a core container feature, and it does not provide the
same features as type-safe configuration properties. The following table
summarizes the features that are supported
by @ConfigurationProperties and @Value :
Feature @ConfigurationProperties
SpEL evaluation No
25. Profiles
Spring Profiles provide a way to segregate parts of your application
configuration and make it be available only in certain environments.
Any @Component or @Configuration can be marked with @Profile to limit
when it is loaded, as shown in the following example:
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ...
spring.profiles.active=dev,hsqldb
You could also specify it on the command line by using the following switch: -
-spring.profiles.active=dev,hsqldb .
For example, when an application with the following properties is run by using
the switch, --spring.profiles.active=prod , the proddb and prodmq profiles
are also activated:
---
my.property: fromyamlfile
---
spring.profiles: prod
spring.profiles.include:
- proddb
- prodmq
26. Logging
Spring Boot uses Commons Logging for all internal logging but leaves the
underlying log implementation open. Default configurations are provided
for Java Util Logging, Log4J2, and Logback. In each case, loggers are pre-
configured to use console output with optional file output also available.
By default, if you use the “Starters”, Logback is used for logging. Appropriate
Logback routing is also included to ensure that dependent libraries that use
Java Util Logging, Commons Logging, Log4J, or SLF4J all work correctly.
There are a lot of logging frameworks available for Java. Do not worry if the above
list seems confusing. Generally, you do not need to change your logging
dependencies and the Spring Boot defaults work just fine.
Alternatively, you can enable a “trace” mode by starting your application with
a --trace flag (or trace=true in your application.properties ). Doing so enables
trace logging for a selection of core loggers (embedded container, Hibernate
schema generation, and the whole Spring portfolio).
%clr(%5p)
Level Color
FATAL Red
ERROR Red
WARN Yellow
INFO Green
DEBUG Green
Level Color
TRACE Green
Alternatively, you can specify the color or style that should be used by
providing it as an option to the conversion. For example, to make the text
yellow, use the following setting:
%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){yellow}
blue
cyan
faint
green
magenta
red
yellow
The following table shows how the logging.* properties can be used together:
one) my.log Writes to the specified log file. Names can be an exact location or relative to the current directo
pecific directory /var/log Writes spring.log to the specified directory. Names can be an exact location or relative to the
Log files rotate when they reach 10 MB and, as with console output, ERROR -
level, WARN -level, and INFO -level messages are logged by default. Size limits
can be changed using the logging.file.max-size property. Previously rotated
files are archived indefinitely unless the logging.file.max-history property has
been set.
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
logging.group.tomcat=org.apache.catalina, org.apache.coyote,
org.apache.tomcat
Once defined, you can change the level for all the loggers in the group with a
single line:
logging.level.tomcat=TRACE
Spring Boot includes the following pre-defined logging groups that can be
used out-of-the-box:
Name Loggers
You can force Spring Boot to use a particular logging system by using
the org.springframework.boot.logging.LoggingSystem system property. The value
should be the fully qualified class name of a LoggingSystem implementation. You
can also disable Spring Boot’s logging configuration entirely by using a value
of none .
When possible, we recommend that you use the -spring variants for your logging
than logback.xml). If you use standard configuration locations, Spring cannot com
There are known classloading issues with Java Util Logging that cause problems
when running from an 'executable jar'. We recommend that you avoid it when
running from an 'executable jar' if at all possible.
To help with the customization, some other properties are transferred from the
Spring Environment to System properties, as described in the following table:
All the supported logging systems can consult System properties when
parsing their configuration files. See the default configurations in spring-
boot.jar for examples:
Logback
Log4j 2
Java Util logging
If you want to use a placeholder in a logging property, you should use Spring
Boot’s syntax and not the syntax of the underlying framework. Notably, if you use
Logback, you should use : as the delimiter between a property name and its default
value and not use :-.
You can add MDC and other ad-hoc content to log lines by overriding only
the LOG_LEVEL_PATTERN (or logging.pattern.level with Logback). For example, if
you use logging.pattern.level=user:%X{user} %5p, then the default log format
contains an MDC entry for "user", if it exists, as shown in the following example.
2015-09-30 12:30:04.031 user:someone INFO 22174 --- [ nio-8080-
exec-0] demo.Controller
Handling authenticated request
Because the standard logback.xml configuration file is loaded too early, you cannot
use extensions in it. You need to either use logback-spring.xmlor define
a logging.config property.
<springProfile name="staging">
<!-- configuration to be enabled when the "staging" profile is
active -->
</springProfile>
<springProfile name="dev | staging">
<!-- configuration to be enabled when the "dev" or "staging"
profiles are active -->
</springProfile>
<springProfile name="!production">
<!-- configuration to be enabled when the "production" profile is
not active -->
</springProfile>
26.7.2 Environment Properties
The <springProperty> tag lets you expose properties from the
Spring Environment for use within Logback. Doing so can be useful if you want
to access values from your application.properties file in your Logback
configuration. The tag works in a similar way to Logback’s
standard <property> tag. However, rather than specifying a direct value , you
specify the source of the property (from the Environment ). If you need to store
the property somewhere other than in local scope, you can use
the scope attribute. If you need a fallback value (in case the property is not set
in the Environment ), you can use the defaultValue attribute. The following
example shows how to expose properties for use within Logback:
27. Internationalization
Spring Boot supports localized messages so that your application can cater to
users of different language preferences. By default, Spring Boot looks for the
presence of a messages resource bundle at the root of the classpath.
The auto-configuration applies when the default properties file for the configured
resource bundle is available (i.e. messages.properties by default). If your
resource bundle contains only language-specific properties files, you are required to
add the default.
The basename of the resource bundle as well as several other attributes can
be configured using the spring.messages namespace, as shown in the
following example:
spring.messages.basename=messages,config.i18n.messages
spring.messages.fallback-to-system-locale=false
28. JSON
Spring Boot provides integration with three JSON mapping libraries:
Gson
Jackson
JSON-B
28.1 Jackson
Auto-configuration for Jackson is provided and Jackson is part
of spring-boot-starter-json . When Jackson is on the classpath
an ObjectMapper bean is automatically configured. Several configuration
properties are provided for customizing the configuration of
the ObjectMapper .
28.2 Gson
Auto-configuration for Gson is provided. When Gson is on the
classpath a Gson bean is automatically configured.
Several spring.gson.* configuration properties are provided for
customizing the configuration. To take more control, one or
more GsonBuilderCustomizer beans can be used.
28.3 JSON-B
Auto-configuration for JSON-B is provided. When the JSON-B API and
an implementation are on the classpath a Jsonb bean will be
automatically configured. The preferred JSON-B implementation is
Apache Johnzon for which dependency management is provided.
If you have not yet developed a Spring Boot web application, you can
follow the "Hello World!" example in the Getting started section.
@RestController
@RequestMapping(value="/users")
public class MyRestController {
@RequestMapping(value="/{user}", method=RequestMethod.GET)
public User getUser(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}/customers",
method=RequestMethod.GET)
List<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@RequestMapping(value="/{user}",
method=RequestMethod.DELETE)
public User deleteUser(@PathVariable Long user) {
// ...
}
Inclusion
of ContentNegotiatingViewResolver and BeanNameViewResolver
beans.
Support for serving static resources, including support for
WebJars (covered later in this document)).
Automatic registration of Converter , GenericConverter ,
and Formatter beans.
Support for HttpMessageConverters (covered later in this
document).
Automatic registration of MessageCodesResolver (covered later in
this document).
Static index.html support.
Custom Favicon support (covered later in this document).
Automatic use of a ConfigurableWebBindingInitializer bean
(covered later in this document).
If you want to keep Spring Boot MVC features and you want to add
additional MVC configuration (interceptors, formatters, view controllers,
and other features), you can add your own @Configuration class of
type WebMvcConfigurer but without @EnableWebMvc . If you wish to
provide custom instances
of RequestMappingHandlerMapping , RequestMappingHandlerAdapter ,
or ExceptionHandlerExceptionResolver , you can declare
a WebMvcRegistrationsAdapter instance to provide such components.
If you want to take complete control of Spring MVC, you can add your
own @Configuration annotated with @EnableWebMvc .
29.1.2 HttpMessageConverters
Spring MVC uses the HttpMessageConverter interface to convert HTTP
requests and responses. Sensible defaults are included out of the box.
For example, objects can be automatically converted to JSON (by
using the Jackson library) or XML (by using the Jackson XML
extension, if available, or by using JAXB if the Jackson XML extension
is not available). By default, strings are encoded in UTF-8 .
import
org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional,
another);
}
import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;
@JsonComponent
public class Example {
29.1.4 MessageCodesResolver
Spring MVC has a strategy for generating error codes for rendering
error messages from binding errors: MessageCodesResolver . If you set
the spring.mvc.message-codes-
resolver.format property PREFIX_ERROR_CODE or POSTFIX_ERROR_CODE ,
Spring Boot creates one for you (see the enumeration
in DefaultMessageCodesResolver.Format ).
spring.mvc.static-path-pattern=/resources/**
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12
This feature has been thoroughly described in a dedicated blog post and in
Spring Framework’s reference documentation.
29.1.6 Welcome Page
Spring Boot supports both static and templated welcome pages. It first
looks for an index.html file in the configured static content locations. If
one is not found, it then looks for an index template. If either is found,
it is automatically used as the welcome page of the application.
spring.mvc.contentnegotiation.favor-parameter=true
If you understand the caveats and would still like your application to
use suffix pattern matching, the following configuration is required:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-suffix-pattern=true
Alternatively, rather than open all suffix patterns, it’s more secure to
just support registered suffix patterns:
spring.mvc.contentnegotiation.favor-path-extension=true
spring.mvc.pathmatch.use-registered-suffix-pattern=true
FreeMarker
Groovy
Thymeleaf
Mustache
When you use one of these templating engines with the default
configuration, your templates are picked up automatically
from src/main/resources/templates .
Depending on how you run your application, IntelliJ IDEA orders the
classpath differently. Running your application in the IDE from its main
method results in a different ordering than when you run your application
by using Maven or Gradle or from its packaged jar. This can cause Spring
Boot to fail to find the templates on the classpath. If you have this problem,
you can reorder the classpath in the IDE to place the module’s classes and
resources first. Alternatively, you can configure the template prefix to
search every templates directory on the classpath, as
follows: classpath*:/templates/.
29.1.11 Error Handling
By default, Spring Boot provides an /error mapping that handles all
errors in a sensible way, and it is registered as a “global” error page in
the servlet container. For machine clients, it produces a JSON
response with details of the error, the HTTP status, and the exception
message. For browser clients, there is a “whitelabel” error view that
renders the same data in HTML format (to customize it, add
a View that resolves to error ). To replace the default behavior
completely, you can implement ErrorController and register a bean
definition of that type or add a bean of type ErrorAttributes to use
the existing mechanism but replace the contents.
@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends
ResponseEntityExceptionHandler {
@ExceptionHandler(YourException.class)
@ResponseBody
ResponseEntity<?>
handleControllerException(HttpServletRequest request, Throwable ex)
{
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new
CustomErrorType(status.value(), ex.getMessage()), status);
}
}
In the preceding example, if YourException is thrown by a controller
defined in the same package as AcmeController , a JSON
representation of the CustomErrorType POJO is used instead of
the ErrorAttributes representation.
For example, to map 404 to a static HTML file, your folder structure
would be as follows:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <other templates>
For more complex mappings, you can also add beans that implement
the ErrorViewResolver interface, as shown in the following example:
public class MyErrorViewResolver implements ErrorViewResolver {
@Override
public ModelAndView resolveErrorView(HttpServletRequest
request,
HttpStatus status, Map<String, Object> model)
{
// Use the request or status to optionally return a
ModelAndView
return ...
}
@Bean
public ErrorPageRegistrar errorPageRegistrar(){
return new MyErrorPageRegistrar();
}
// ...
@Override
public void registerErrorPages(ErrorPageRegistry registry)
{
registry.addErrorPages(new
ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
}
}
If you register an ErrorPage with a path that ends up being handled by
a Filter (as is common with some non-Spring web frameworks, like
Jersey and Wicket), then the Filter has to be explicitly registered as
an ERROR dispatcher, as shown in the following example:
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean registration = new
FilterRegistrationBean();
registration.setFilter(new MyFilter());
...
registration.setDispatcherTypes(EnumSet.allOf(DispatcherTyp
e.class));
return registration;
}
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry
registry) {
registry.addMapping("/api/**");
}
};
}
}
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long
user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse>
monoRouterFunction(UserHandler userHandler) {
return
route(GET("/{user}").and(accept(APPLICATION_JSON)),
userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_J
SON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)),
userHandler::deleteUser);
}
@Component
public class UserHandler {
Configuring codecs
for HttpMessageReader and HttpMessageWriter instances
(described later in this document).
Support for serving static resources, including support for
WebJars (described later in this document).
If you want to keep Spring Boot WebFlux features and you want to add
additional WebFlux configuration, you can add your
own @Configuration class of
type WebFluxConfigurer but without @EnableWebFlux .
If you want to take complete control of Spring WebFlux, you can add
your own @Configuration annotated with @EnableWebFlux .
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}
By default, resources are mapped on /** , but you can tune that by
setting the spring.webflux.static-path-pattern property. For
instance, relocating all resources to /resources/** can be achieved
as follows:
spring.webflux.static-path-pattern=/resources/**
FreeMarker
Thymeleaf
Mustache
When you use one of these templating engines with the default
configuration, your templates are picked up automatically
from src/main/resources/templates .
@Override
protected RouterFunction<ServerResponse>
getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate,
anotherHandler);
}
For example, to map 404 to a static HTML file, your folder structure
would be as follows:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.mustache
+- <other templates>
29.2.6 Web Filters
Spring WebFlux provides a WebFilter interface that can be
implemented to filter HTTP request-response
exchanges. WebFilter beans found in the application context will be
automatically used to filter each exchange.
Where the order of the filters is important they can
implement Ordered or be annotated with @Order . Spring Boot auto-
configuration may configure web filters for you. When it does so, the
orders shown in the following table will be used:
Web Filter Order
MetricsWebFilter Ordere
HttpTraceWebFilter Ordere
@Component
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(Endpoint.class);
}
@Component
@Path("/hello")
public class Endpoint {
@GET
public String message() {
return "Hello";
}
Spring Boot ships with many auto-configurations that may define Filter
beans. Here are a few examples of Filters and their respective order
(lower order value means higher precedence):
OrderedCharacterEncodingFilter Ordered.
WebMvcMetricsFilter Ordered.
ErrorPageFilter Ordered.
HttpTraceFilter Ordered.
import
org.springframework.boot.web.server.WebServerFactoryCustomizer;
import
org.springframework.boot.web.servlet.server.ConfigurableServletWebS
erverFactory;
import org.springframework.stereotype.Component;
@Component
public class CustomizationBean implements
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory
server) {
server.setPort(9000);
}
}
TomcatServletWebServerFactory, JettyServletWebServerFacto
ry and UndertowServletWebServerFactory are dedicated variants
of ConfigurableServletWebServerFactory that have additional
customization setter methods for Tomcat, Jetty and Undertow respectively.
Customizing ConfigurableServletWebServerFactory Directly
If the preceding customization techniques are too limited, you can
register
the TomcatServletWebServerFactory , JettyServletWebServerFactory ,
or UndertowServletWebServerFactory bean yourself.
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new
TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notfound.html"));
return factory;
}
With Jetty and Tomcat, it should work if you use war packaging.
An executable war will work when launched with java -jar , and
will also be deployable to any standard container. JSPs are not
supported when using an executable jar.
Undertow does not support JSPs.
Creating a custom error.jsp page does not override the default
view for error handling. Custom error pages should be used
instead.
There is a JSP sample so that you can see how to set things up.
By default, those resources will be also shared with the Reactor Netty
and Jetty clients for optimal performances, given:
30. Security
If Spring Security is on the classpath, then web applications are
secured by default. Spring Boot relies on Spring Security’s content-
negotiation strategy to determine whether to
use httpBasic or formLogin . To add method-level security to a web
application, you can also add @EnableGlobalMethodSecurity with your
desired settings. Additional information can be found in the Spring
Security Reference Guide.
@Bean
public SecurityWebFilterChain
springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.matchers(PathRequest.toStaticResources().atCommonLocations
()).permitAll()
.pathMatchers("/foo", "/bar")
.authenticated().and()
.formLogin().and()
.build();
}
30.3 OAuth2
OAuth2 is a widely used authorization framework that is supported by
Spring.
30.3.1 Client
If you have spring-security-oauth2-client on your classpath, you
can take advantage of some auto-configuration to make it easy to set
up an OAuth2/Open ID Connect clients. This configuration makes use
of the properties under OAuth2ClientProperties . The same properties
are applicable to both servlet and reactive applications.
You can register multiple OAuth2 clients and providers under
the spring.security.oauth2.client prefix, as shown in the following
example:
spring.security.oauth2.client.registration.my-client-1.client-
id=abcd
spring.security.oauth2.client.registration.my-client-1.client-
secret=password
spring.security.oauth2.client.registration.my-client-1.client-
name=Client for user scope
spring.security.oauth2.client.registration.my-client-1.provider=my-
oauth-provider
spring.security.oauth2.client.registration.my-client-1.scope=user
spring.security.oauth2.client.registration.my-client-1.redirect-
uri-template=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-1.client-
authentication-method=basic
spring.security.oauth2.client.registration.my-client-
1.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.my-client-2.client-
id=abcd
spring.security.oauth2.client.registration.my-client-2.client-
secret=password
spring.security.oauth2.client.registration.my-client-2.client-
name=Client for email scope
spring.security.oauth2.client.registration.my-client-2.provider=my-
oauth-provider
spring.security.oauth2.client.registration.my-client-2.scope=email
spring.security.oauth2.client.registration.my-client-2.redirect-
uri-template=https://my-redirect-uri.com
spring.security.oauth2.client.registration.my-client-2.client-
authentication-method=basic
spring.security.oauth2.client.registration.my-client-
2.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.my-oauth-
provider.authorization-uri=http://my-auth-server/oauth/authorize
spring.security.oauth2.client.provider.my-oauth-provider.token-
uri=http://my-auth-server/oauth/token
spring.security.oauth2.client.provider.my-oauth-provider.user-info-
uri=http://my-auth-server/userinfo
spring.security.oauth2.client.provider.my-oauth-provider.user-info-
authentication-method=header
spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-
uri=http://my-auth-server/token_keys
spring.security.oauth2.client.provider.my-oauth-provider.user-name-
attribute=name
spring.security.oauth2.client.provider.oidc-provider.issuer-
uri=https://dev-123456.oktapreview.com/oauth2/default/
@Override
protected void configure(HttpSecurity http) throws
Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login()
.redirectionEndpoint()
.baseUri("/custom-callback");
}
}
OAuth2 client registration for common providers
For common OAuth2 and OpenID providers, including Google, Github,
Facebook, and Okta, we provide a set of provider defaults
( google , github , facebook , and okta , respectively).
spring.security.oauth2.client.registration.my-client.client-id=abcd
spring.security.oauth2.client.registration.my-client.client-
secret=password
spring.security.oauth2.client.registration.my-
client.provider=google
spring.security.oauth2.client.registration.google.client-id=abcd
spring.security.oauth2.client.registration.google.client-
secret=password
30.3.2 Resource Server
If you have spring-security-oauth2-resource-server on your
classpath, Spring Boot can set up an OAuth2 Resource Server as long
as a JWK Set URI or OIDC Issuer URI is specified, as shown in the
following examples:
spring.security.oauth2.resourceserver.jwt.jwk-set-
uri=https://example.com/oauth2/default/v1/keys
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-
123456.oktapreview.com/oauth2/default/
The same properties are applicable for both servlet and reactive
applications.
Alternatively, you can define your own JwtDecoder bean for servlet
applications or a ReactiveJwtDecoder for reactive applications.
30.3.3 Authorization Server
Currently, Spring Security does not provide support for implementing
an OAuth 2.0 Authorization Server. However, this functionality is
available from the Spring Security OAuth project, which will eventually
be superseded by Spring Security completely. Until then, you can use
the spring-security-oauth2-autoconfigure module to easily set up an
OAuth 2.0 authorization server; see its documentation for instructions.
See the “How-to” section for more advanced examples, typically to take
full control over the configuration of the DataSource.
31.1.1 Embedded Database Support
It is often convenient to develop applications by using an in-memory
embedded database. Obviously, in-memory databases do not provide
persistent storage. You need to populate your database when your
application starts and be prepared to throw away data when your
application ends.
The “How-to” section includes a section on how to initialize a database.
If you are using this feature in your tests, you may notice that the same
database is reused by your whole test suite regardless of the number of
application contexts that you use. If you want to make sure that each
context has a separate embedded database, you should
set spring.datasource.generate-unique-name to true.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
</dependency>
You can bypass that algorithm completely and specify the connection pool
to use by setting the spring.datasource.type property. This is
especially important if you run your application in a Tomcat container,
as tomcat-jdbc is provided by default.
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.jndi-name=java:jboss/datasources/customers
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
private final JdbcTemplate jdbcTemplate;
@Autowired
public MyBean(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// ...
spring.jdbc.template.max-rows=500
package com.example.myapp.domain;
import java.io.Serializable;
import javax.persistence.*;
@Entity
public class City implements Serializable {
@Id
@GeneratedValue
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String state;
protected City() {
// no-args constructor required by JPA spec
// this one is protected since it shouldn't be used
directly
}
// ... etc
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
We have barely scratched the surface of Spring Data JPA. For complete
details, see the Spring Data JPA reference documentation.
31.3.3 Creating and Dropping JPA Databases
By default, JPA databases are automatically created only if you use
an embedded database (H2, HSQL, or Derby). You can explicitly
configure JPA settings by using spring.jpa.* properties. For example,
to create and drop tables you can add the following line to
your application.properties :
spring.jpa.hibernate.ddl-auto=create-drop
Hibernate’s own internal property name for this (if you happen to
remember it better) is hibernate.hbm2ddl.auto. You can set it, along
with other Hibernate native properties, by
using spring.jpa.properties.* (the prefix is stripped before adding
them to the entity manager). The following line shows an example of
setting JPA properties for Hibernate:
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
If you are not using Spring Boot’s developer tools but would still like to
make use of H2’s console, you can configure
the spring.h2.console.enabledproperty with a value of true.
<plugin>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen-maven</artifactId>
<executions>
...
</executions>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<jdbc>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:~/yourdatabase</url>
</jdbc>
<generator>
...
</generator>
</configuration>
</plugin>
31.6.2 Using DSLContext
The fluent API offered by jOOQ is initiated through
the org.jooq.DSLContext interface. Spring Boot auto-configures
a DSLContext as a Spring Bean and connects it to your
application DataSource . To use the DSLContext , you can @Autowire it,
as shown in the following example:
@Component
public class JooqExample implements CommandLineRunner {
private final DSLContext create;
@Autowired
public JooqExample(DSLContext dslContext) {
this.create = dslContext;
}
You can then use the DSLContext to construct your queries, as shown
in the following example:
Spring Boot can only auto-configure dialects supported by the open source
version of jOOQ.
31.6.4 Customizing jOOQ
More advanced customizations can be achieved by defining your
own @Bean definitions, which is used when the jOOQ Configuration is
created. You can define beans for the following jOOQ Types:
ConnectionProvider
ExecutorProvider
TransactionProvider
RecordMapperProvider
RecordUnmapperProvider
RecordListenerProvider
ExecuteListenerProvider
VisitListenerProvider
TransactionListenerProvider
32.1 Redis
Redis is a cache, message broker, and richly-featured key-value store.
Spring Boot offers basic auto-configuration for
the Lettuce and Jedis client libraries and the abstractions on top of
them provided by Spring Data Redis.
There is a spring-boot-starter-data-redis “Starter” for collecting the
dependencies in a convenient way. By default, it uses Lettuce. That
starter handles both traditional and reactive applications.
@Component
public class MyBean {
@Autowired
public MyBean(StringRedisTemplate template) {
this.template = template;
}
// ...
32.2 MongoDB
MongoDB is an open-source NoSQL document database that uses a
JSON-like schema instead of traditional table-based relational data.
Spring Boot offers several conveniences for working with MongoDB,
including the spring-boot-starter-data-mongodb and spring-boot-
starter-data-mongodb-reactive “Starters”.
import org.springframework.data.mongodb.MongoDbFactory;
import com.mongodb.DB;
@Component
public class MyBean {
@Autowired
public MyBean(MongoDbFactory mongo) {
this.mongo = mongo;
}
// ...
spring.data.mongodb.uri=mongodb://user:[email protected]:12
345,mongo2.example.com:23456/test
spring.data.mongodb.host=mongoserver
spring.data.mongodb.port=27017
If spring.data.mongodb.port
is not specified, the default
of 27017 is used. You could delete
this line from the example shown
earlier.
If you do not use Spring Data Mongo, you can
inject com.mongodb.MongoClient beans instead of
using MongoDbFactory. If you want to take complete control of
establishing the MongoDB connection, you can also declare your
own MongoDbFactory or MongoClient bean.
If you are using the reactive driver, Netty is required for SSL. The auto-
configuration configures this factory automatically if Netty is available and
the factory to use hasn’t been customized already.
32.2.2 MongoTemplate
Spring Data MongoDB provides a MongoTemplate class that is very
similar in its design to Spring’s JdbcTemplate . As with JdbcTemplate ,
Spring Boot auto-configures a bean for you to inject the template, as
follows:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Autowired
public MyBean(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
// ...
package com.example.myapp.domain;
import org.springframework.data.domain.*;
import org.springframework.data.repository.*;
For complete details of Spring Data MongoDB, including its rich object
mapping technologies, refer to its reference documentation.
32.2.4 Embedded Mongo
Spring Boot offers auto-configuration for Embedded Mongo. To use it
in your Spring Boot application, add a dependency
on de.flapdoodle.embed:de.flapdoodle.embed.mongo .
The port that Mongo listens on can be configured by setting
the spring.data.mongodb.port property. To use a randomly allocated
free port, use a value of 0. The MongoClient created
by MongoAutoConfiguration is automatically configured to use the
randomly allocated port.
32.3 Neo4j
Neo4j is an open-source NoSQL graph database that uses a rich data
model of nodes connected by first class relationships, which is better
suited for connected big data than traditional RDBMS approaches.
Spring Boot offers several conveniences for working with Neo4j,
including the spring-boot-starter-data-neo4j “Starter”.
@Component
public class MyBean {
// ...
spring.data.neo4j.uri=bolt://my-server:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
You can take full control over the session creation by adding
a org.neo4j.ogm.config.Configuration @Bean . Also, adding
a @Bean of type SessionFactory disables the auto-configuration and
gives you full control.
As the embedded Neo4j OGM driver does not provide the Neo4j kernel
itself, you have to declare org.neo4j:neo4j as dependency yourself.
Refer to the Neo4j OGM documentation for a list of compatible versions.
The embedded driver takes precedence over the other drivers when
there are multiple drivers on the classpath. You can explicitly disable
the embedded mode by
setting spring.data.neo4j.embedded.enabled=false .
You can enable persistence for the embedded mode by providing a path to
a database file in your configuration,
e.g. spring.data.neo4j.uri=file://var/tmp/graph.db.
32.3.3 Neo4jSession
By default, if you are running a web application, the session is bound
to the thread for the entire processing of the request (that is, it uses the
"Open Session in View" pattern). If you do not want this behavior, add
the following line to your application.properties file:
spring.data.neo4j.open-in-view=false
32.3.4 Spring Data Neo4j Repositories
Spring Data includes repository support for Neo4j.
Spring Data Neo4j shares the common infrastructure with Spring Data
JPA as many other Spring Data modules do. You could take the JPA
example from earlier and define City as Neo4j
OGM @NodeEntity rather than JPA @Entity and the repository
abstraction works in the same way, as shown in the following example:
package com.example.myapp.domain;
import java.util.Optional;
import org.springframework.data.neo4j.repository.*;
For complete details of Spring Data Neo4j, including its object mapping
technologies, refer to the reference documentation.
32.4 Gemfire
Spring Data Gemfire provides convenient Spring-friendly tools for
accessing the Pivotal Gemfire data management platform. There is
a spring-boot-starter-data-gemfire “Starter” for collecting the
dependencies in a convenient way. There is currently no auto-
configuration support for Gemfire, but you can enable Spring Data
Repositories with a single annotation: @EnableGemfireRepositories .
32.5 Solr
Apache Solr is a search engine. Spring Boot offers basic auto-
configuration for the Solr 5 client library and the abstractions on top of
it provided by Spring Data Solr. There is a spring-boot-starter-data-
solr “Starter” for collecting the dependencies in a convenient way.
@Component
public class MyBean {
@Autowired
public MyBean(SolrClient solr) {
this.solr = solr;
}
// ...
If you add your own @Bean of type SolrClient , it replaces the default.
32.6 Elasticsearch
Elasticsearch is an open source, distributed, RESTful search and
analytics engine. Spring Boot offers basic auto-configuration for
Elasticsearch.
Spring Boot supports several HTTP clients:
The official Java "Low Level" and "High Level" REST clients
Jest
The transport client is still being used by Spring Data Elasticsearch,
which you can start using with the spring-boot-starter-data-
elasticsearch “Starter”.
spring.elasticsearch.rest.uris=https://search.example.com:9200
spring.elasticsearch.rest.username=user
spring.elasticsearch.rest.password=secret
spring.elasticsearch.jest.uris=https://search.example.com:9200
spring.elasticsearch.jest.read-timeout=10000
spring.elasticsearch.jest.username=user
spring.elasticsearch.jest.password=secret
You can also register an arbitrary number of beans that
implement HttpClientConfigBuilderCustomizer for more advanced
customizations. The following example tunes additional HTTP settings:
@Override
public void customize(HttpClientConfig.Builder builder) {
builder.maxTotalConnection(100).defaultMaxTotalConnectionPe
rRoute(5);
}
spring.data.elasticsearch.cluster-nodes=localhost:9300
@Component
public class MyBean {
// ...
}
If you add your
own ElasticsearchTemplate or TransportClient @Bean , it replaces the
default.
32.7 Cassandra
Cassandra is an open source, distributed database management
system designed to handle large amounts of data across many
commodity servers. Spring Boot offers auto-configuration for
Cassandra and the abstractions on top of it provided by Spring Data
Cassandra. There is a spring-boot-starter-data-cassandra “Starter”
for collecting the dependencies in a convenient way.
@Component
public class MyBean {
@Autowired
public MyBean(CassandraTemplate template) {
this.template = template;
}
// ...
32.8 Couchbase
Couchbase is an open-source, distributed, multi-model NoSQL
document-oriented database that is optimized for interactive
applications. Spring Boot offers auto-configuration for Couchbase and
the abstractions on top of it provided by Spring Data Couchbase.
There are spring-boot-starter-data-couchbase and spring-boot-
starter-data-couchbase-reactive “Starters” for collecting the
dependencies in a convenient way.
spring.couchbase.bootstrap-hosts=my-host-1,192.168.1.123
spring.couchbase.bucket.name=my-bucket
spring.couchbase.bucket.password=secret
You need to provide at least the bootstrap host(s), in which case the bucket
name is default and the password is an empty String. Alternatively, you
can define your
own org.springframework.data.couchbase.config.CouchbaseC
onfigurer @Bean to take control over the whole configuration.
spring.couchbase.env.timeouts.connect=3000
spring.couchbase.env.ssl.key-store=/location/of/keystore.jks
spring.couchbase.env.ssl.key-store-password=secret
@Component
public class MyBean {
@Autowired
public MyBean(CouchbaseTemplate template) {
this.template = template;
}
// ...
There are a few beans that you can define in your own configuration to
override those provided by the auto-configuration:
@Configuration
public class SomeConfiguration {
@Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS)
public CustomConversions myCustomConversions() {
return new CustomConversions(...);
}
// ...
32.9 LDAP
LDAP (Lightweight Directory Access Protocol) is an open, vendor-
neutral, industry standard application protocol for accessing and
maintaining distributed directory information services over an IP
network. Spring Boot offers auto-configuration for any compliant LDAP
server as well as support for the embedded in-memory LDAP server
from UnboundID.
LDAP abstractions are provided by Spring Data LDAP. There is
a spring-boot-starter-data-ldap “Starter” for collecting the
dependencies in a convenient way.
spring.ldap.urls=ldap://myserver:1235
spring.ldap.username=admin
spring.ldap.password=secret
@Component
public class MyBean {
@Autowired
public MyBean(LdapTemplate template) {
this.template = template;
}
// ...
}
32.9.3 Embedded In-memory LDAP Server
For testing purposes, Spring Boot supports auto-configuration of an in-
memory LDAP server from UnboundID. To configure the server, add a
dependency to com.unboundid:unboundid-ldapsdk and declare
a base-dn property, as follows:
spring.ldap.embedded.base-dn=dc=spring,dc=io
It is possible to define multiple base-dn values, however, since
distinguished names usually contain commas, they must be defined using
the correct notation.
In yaml files, you can use the yaml list notation:
spring.ldap.embedded.base-dn:
- dc=spring,dc=io
- dc=pivotal,dc=io
In properties files, you must include the index as part of the property name:
spring.ldap.embedded.base-dn[0]=dc=spring,dc=io
spring.ldap.embedded.base-dn[1]=dc=pivotal,dc=io
By default, the server starts on a random port and triggers the regular
LDAP support. There is no need to specify
a spring.ldap.urls property.
32.10 InfluxDB
InfluxDB is an open-source time series database optimized for fast,
high-availability storage and retrieval of time series data in fields such
as operations monitoring, application metrics, Internet-of-Things
sensor data, and real-time analytics.
spring.influx.url=https://172.0.0.1:8086
If the connection to InfluxDB requires a user and password, you can
set the spring.influx.user and spring.influx.password properties
accordingly.
InfluxDB relies on OkHttp. If you need to tune the http
client InfluxDB uses behind the scenes, you can register
an InfluxDbOkHttpClientBuilderProvider bean.
33. Caching
The Spring Framework provides support for transparently adding
caching to an application. At its core, the abstraction applies caching to
methods, thus reducing the number of executions based on the
information available in the cache. The caching logic is applied
transparently, without any interference to the invoker. Spring Boot
auto-configures the cache infrastructure as long as caching support is
enabled via the @EnableCaching annotation.
Check the relevant section of the Spring Framework reference for more
details.
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class MathService {
@Cacheable("piDecimals")
public int computePiDecimal(int i) {
// ...
}
Caution
You can also use the standard JSR-107 (JCache) annotations (such
as @CacheResult ) transparently. However, we strongly advise you to
not mix and match the Spring Cache and JCache annotations.
If you do not add any specific cache library, Spring Boot auto-
configures a simple provider that uses concurrent maps in memory.
When a cache is required (such as piDecimals in the preceding
example), this provider creates it for you. The simple provider is not
really recommended for production usage, but it is great for getting
started and making sure that you understand the features. When you
have made up your mind about the cache provider to use, please
make sure to read its documentation to figure out how to configure the
caches that your application uses. Nearly all providers require you to
explicitly configure every cache that you use in the application. Some
offer a way to customize the default caches defined by
the spring.cache.cache-names property.
1. Generic
2. JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and
others)
3. EhCache 2.x
4. Hazelcast
5. Infinispan
6. Couchbase
7. Redis
8. Caffeine
9. Simple
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager>
cacheManagerCustomizer() {
return new
CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager
cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}
spring.cache.ehcache.config=classpath:config/another-config.xml
33.1.4 Hazelcast
Spring Boot has general support for Hazelcast. If
a HazelcastInstance has been auto-configured, it is automatically
wrapped in a CacheManager .
33.1.5 Infinispan
Infinispan has no default configuration file location, so it must be
specified explicitly. Otherwise, the default bootstrap is used.
spring.cache.infinispan.config=infinispan.xml
spring.cache.cache-names=cache1,cache2
@Configuration
public class CouchbaseCacheConfiguration {
@Bean
public Bucket anotherBucket() {
return this.cluster.openBucket("another", "secret");
}
@Bean
public CacheManagerCustomizer<CouchbaseCacheManager>
cacheManagerCustomizer() {
return c -> {
c.prepareCache("cache3",
CacheBuilder.newInstance(anotherBucket())
.withExpiration(2));
};
}
spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000
By default, a key prefix is added so that, if two separate caches use the
same key, Redis does not have overlapping keys and cannot return invalid
values. We strongly recommend keeping this setting enabled if you create
your own RedisCacheManager.
spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
If a com.github.benmanes.caffeine.cache.CacheLoader bean is
defined, it is automatically associated to the CaffeineCacheManager .
Since the CacheLoader is going to be associated with all caches
managed by the cache manager, it must be defined
as CacheLoader<Object, Object> . The auto-configuration ignores any
other generic type.
33.1.9 Simple
If none of the other providers can be found, a simple implementation
using a ConcurrentHashMap as the cache store is configured. This is
the default if no caching library is present in your application. By
default, caches are created as needed, but you can restrict the list of
available caches by setting the cache-names property. For instance, if
you want only cache1 and cache2 caches, set the cache-
names property as follows:
spring.cache.cache-names=cache1,cache2
If you do so and your application uses a cache not listed, then it fails at
runtime when the cache is needed, but not on startup. This is similar to
the way the "real" cache providers behave if you use an undeclared
cache.
33.1.10 None
When @EnableCaching is present in your configuration, a suitable
cache configuration is expected as well. If you need to disable caching
altogether in certain environments, force the cache type to none to use
a no-op implementation, as shown in the following example:
spring.cache.type=none
34. Messaging
The Spring Framework provides extensive support for integrating with
messaging systems, from simplified use of the JMS API
using JmsTemplate to a complete infrastructure to receive messages
asynchronously. Spring AMQP provides a similar feature set for the
Advanced Message Queuing Protocol. Spring Boot also provides auto-
configuration options for RabbitTemplate and RabbitMQ. Spring
WebSocket natively includes support for STOMP messaging, and
Spring Boot has support for that through starters and a small amount
of auto-configuration. Spring Boot also has support for Apache Kafka.
34.1 JMS
The javax.jms.ConnectionFactory interface provides a standard
method of creating a javax.jms.Connection for interacting with a JMS
broker. Although Spring needs a ConnectionFactory to work with JMS,
you generally need not use it directly yourself and can instead rely on
higher level messaging abstractions. (See therelevant section of the
Spring Framework reference documentation for details.) Spring Boot
also auto-configures the necessary infrastructure to send and receive
messages.
spring.activemq.broker-url=tcp://192.168.1.210:9876
spring.activemq.user=admin
spring.activemq.password=secret
spring.jms.cache.session-cache-size=5
spring.activemq.pool.enabled=true
spring.activemq.pool.max-connections=50
spring.artemis.mode=native
spring.artemis.host=192.168.1.210
spring.artemis.port=9876
spring.artemis.user=admin
spring.artemis.password=secret
When embedding the broker, you can choose if you want to enable
persistence and list the destinations that should be made available.
These can be specified as a comma-separated list to create them with
the default options, or you can define bean(s) of
type org.apache.activemq.artemis.jms.server.config.JMSQueueConfi
guration or org.apache.activemq.artemis.jms.server.config.TopicC
onfiguration , for advanced queue and topic configurations,
respectively.
spring.artemis.pool.enabled=true
spring.artemis.pool.max-connections=50
spring.jms.jndi-name=java:/MyConnectionFactory
34.1.4 Sending a Message
Spring’s JmsTemplate is auto-configured, and you can autowire it
directly into your own beans, as shown in the following example:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Autowired
public MyBean(JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
// ...
@Component
public class MyBean {
@JmsListener(destination = "someQueue")
public void processMessage(String content) {
// ...
}
@Configuration
static class JmsConfiguration {
@Bean
public DefaultJmsListenerContainerFactory myFactory(
DefaultJmsListenerContainerFactoryConfigurer
configurer) {
DefaultJmsListenerContainerFactory factory =
new
DefaultJmsListenerContainerFactory();
configurer.configure(factory, connectionFactory());
factory.setMessageConverter(myMessageConverter());
return factory;
}
Then you can use the factory in any @JmsListener -annotated method
as follows:
@Component
public class MyBean {
@JmsListener(destination = "someQueue",
containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
34.2 AMQP
The Advanced Message Queuing Protocol (AMQP) is a platform-
neutral, wire-level protocol for message-oriented middleware. The
Spring AMQP project applies core Spring concepts to the development
of AMQP-based messaging solutions. Spring Boot offers several
conveniences for working with AMQP through RabbitMQ, including
the spring-boot-starter-amqp “Starter”.
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=secret
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyBean {
@Autowired
public MyBean(AmqpAdmin amqpAdmin, AmqpTemplate
amqpTemplate) {
this.amqpAdmin = amqpAdmin;
this.amqpTemplate = amqpTemplate;
}
// ...
spring.rabbitmq.template.retry.enabled=true
spring.rabbitmq.template.retry.initial-interval=2s
@Component
public class MyBean {
@RabbitListener(queues = "someQueue")
public void processMessage(String content) {
// ...
}
It does not matter which container type you chose. Those two beans are
exposed by the auto-configuration.
@Configuration
static class RabbitConfiguration {
@Bean
public SimpleRabbitListenerContainerFactory myFactory(
SimpleRabbitListenerContainerFactoryConfigurer configurer)
{
SimpleRabbitListenerContainerFactory factory =
new
SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setMessageConverter(myMessageConverter());
return factory;
}
@Component
public class MyBean {
@RabbitListener(queues = "someQueue",
containerFactory="myFactory")
public void processMessage(String content) {
// ...
}
}
You can enable retries to handle situations where your listener throws
an exception. By default, RejectAndDontRequeueRecoverer is used, but
you can define a MessageRecoverer of your own. When retries are
exhausted, the message is rejected and either dropped or routed to a
dead-letter exchange if the broker is configured to do so. By default,
retries are disabled. You can also customize
the RetryTemplate programmatically by declaring
a RabbitRetryTemplateCustomizer bean.
Important
By default, if retries are disabled and the listener throws an exception, the
delivery is retried indefinitely. You can modify this behavior in two ways:
Set thedefaultRequeueRejected property to false so that zero re-
deliveries are attempted or throw
an AmqpRejectAndDontRequeueException to signal the message
should be rejected. The latter is the mechanism used when retries are
enabled and the maximum number of delivery attempts is reached.
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=myGroup
@Component
public class MyBean {
@Autowired
public MyBean(KafkaTemplate kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
// ...
@Component
public class MyBean {
@KafkaListener(topics = "someTopic")
public void processMessage(String content) {
// ...
}
@Configuration
@EnableKafkaStreams
static class KafkaStreamsExampleConfiguration {
@Bean
public KStream<Integer, String> kStream(StreamsBuilder
streamsBuilder) {
KStream<Integer, String> stream =
streamsBuilder.stream("ks1In");
stream.map((k, v) -> new KeyValue<>(k,
v.toUpperCase())).to("ks1Out",
Produced.with(Serdes.Integer(), new
JsonSerde<>()));
return stream;
}
spring.kafka.properties.prop.one=first
spring.kafka.admin.properties.prop.two=second
spring.kafka.consumer.properties.prop.three=third
spring.kafka.producer.properties.prop.four=fourth
spring.kafka.streams.properties.prop.five=fifth
spring.kafka.consumer.value-
deserializer=org.springframework.kafka.support.serializer.JsonDeser
ializer
spring.kafka.consumer.properties.spring.json.value.default.type=com
.example.Invoice
spring.kafka.consumer.properties.spring.json.trusted.packages=com.e
xample,org.acme
spring.kafka.producer.value-
serializer=org.springframework.kafka.support.serializer.JsonSeriali
zer
spring.kafka.producer.properties.spring.json.add.type.headers=false
If you need to call remote REST services from your application, you
can use the Spring Framework’s RestTemplate class.
Since RestTemplate instances often need to be customized before being
used, Spring Boot does not provide any single auto-
configured RestTemplate bean. It does, however, auto-configure
a RestTemplateBuilder , which can be used to
create RestTemplate instances when needed. The auto-
configured RestTemplateBuilder ensures that
sensible HttpMessageConverters are applied to RestTemplate instances.
@Service
public class MyService {
@Override
public void customize(RestTemplate restTemplate) {
HttpHost proxy = new HttpHost("proxy.example.com");
HttpClient httpClient = HttpClientBuilder.create()
.setRoutePlanner(new
DefaultProxyRoutePlanner(proxy) {
@Override
public HttpHost
determineProxy(HttpHost target,
HttpRequest
request, HttpContext context)
throws
HttpException {
if
(target.getHostName().equals("192.168.0.5")) {
return null;
}
return
super.determineProxy(target, request, context);
}
}).build();
restTemplate.setRequestFactory(
new
HttpComponentsClientHttpRequestFactory(httpClient));
}
Finally, the most extreme (and rarely used) option is to create your
own RestTemplateBuilder bean. Doing so switches off the auto-
configuration of a RestTemplateBuilder and prevents
any RestTemplateCustomizer beans from being used.
36. Calling REST Services with WebClient
If you have Spring WebFlux on your classpath, you can also choose to
use WebClient to call remote REST services. Compared to RestTemplate , this
client has a more functional feel and is fully reactive. You can learn more
about the WebClient in the dedicated section in the Spring Framework docs.
@Service
public class MyService {
.retrieve().bodyToMono(Details.class);
}
You can learn more about the WebClient configuration options in the Spring
Framework reference documentation.
Finally, you can fall back to the original API and use WebClient.create() . In that
case, no auto-configuration or WebClientCustomizer is applied.
37. Validation
The method validation feature supported by Bean Validation 1.1 is
automatically enabled as long as a JSR-303 implementation (such as
Hibernate validator) is on the classpath. This lets bean methods be annotated
with javax.validation constraints on their parameters and/or on their return
value. Target classes with such annotated methods need to be annotated with
the @Validated annotation at the type level for their methods to be searched
for inline constraint annotations.
For instance, the following service triggers the validation of the first argument,
making sure its size is between 8 and 10:
@Service
@Validated
public class MyBean {
See the reference documentation for a detailed explanation of how you can
use JavaMailSender.
In particular, certain default timeout values are infinite, and you may want to
change that to avoid having a thread blocked by an unresponsive mail server,
as shown in the following example:
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=3000
spring.mail.properties.mail.smtp.writetimeout=5000
spring.mail.jndi-name=mail/Session
To ensure that multiple transaction managers can safely coordinate the same
resource managers, each Atomikos instance must be configured with a unique ID.
By default, this ID is the IP address of the machine on which Atomikos is running.
To ensure uniqueness in production, you should configure
the spring.jta.transaction-manager-id property with a different value for
each instance of your application.
By default, Bitronix transaction log files ( part1.btm and part2.btm ) are written
to a transaction-logs directory in your application home directory. You can
customize the location of this directory by setting the spring.jta.log-
dir property. Properties starting with spring.jta.bitronix.properties are
also bound to the bitronix.tm.Configuration bean, allowing for complete
customization. See the Bitronix documentation for details.
To ensure that multiple transaction managers can safely coordinate the same
resource managers, each Bitronix instance must be configured with a unique ID. By
default, this ID is the IP address of the machine on which Bitronix is running. To
ensure uniqueness in production, you should configure
the spring.jta.transaction-manager-id property with a different value for
each instance of your application.
// Inject the XA aware ConnectionFactory (uses the alias and injects the
same as above)
@Autowired
@Qualifier("xaJmsConnectionFactory")
private ConnectionFactory xaConnectionFactory;
// Inject the non-XA aware ConnectionFactory
@Autowired
@Qualifier("nonXaJmsConnectionFactory")
private ConnectionFactory nonXaConnectionFactory;
40. Hazelcast
If Hazelcast is on the classpath and a suitable configuration is found, Spring
Boot auto-configures a HazelcastInstance that you can inject in your application.
spring.hazelcast.config=classpath:config/my-hazelcast.xml
Otherwise, Spring Boot tries to find the Hazelcast configuration from the
default locations: hazelcast.xml in the working directory or at the root of the
classpath. We also check if the hazelcast.config system property is set. See
the Hazelcast documentation for more details.
If hazelcast-client is present on the classpath, Spring Boot first attempts to
create a client by checking the following configuration options:
Beans of the following types are automatically picked up and associated with
the Scheduler :
spring.quartz.job-store-type=jdbc
When the JDBC store is used, the schema can be initialized on startup, as
shown in the following example:
spring.quartz.jdbc.initialize-schema=always
By default, the database is detected and initialized by using the standard scripts
provided with the Quartz library. These scripts drop existing tables, deleting all
triggers on every restart. It is also possible to provide a custom script by setting
the spring.quartz.jdbc.schema property.
To have Quartz use a DataSource other than the application’s main DataSource ,
declare a DataSource bean, annotating its @Bean method with @QuartzDataSource .
Doing so ensures that the Quartz-specific DataSource is used by both
the SchedulerFactoryBean and for schema initialization.
In particular, an Executor bean is not associated with the scheduler as Quartz offers
a way to configure the scheduler via spring.quartz.properties. If you need to
customize the task executor, consider
implementing SchedulerFactoryBeanCustomizer.
Jobs can define setters to inject data map properties. Regular beans can also
be injected in a similar manner, as shown in the following example:
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
...
}
If you have defined a custom Executor in the context, regular task execution
(i.e. @EnableAsync) will use it transparently but the Spring MVC support will not
be configured as it requires an AsyncTaskExecutor implementation
(named applicationTaskExecutor). Depending on your target arrangement,
you could change your Executor into a ThreadPoolTaskExecutor or define
both a ThreadPoolTaskExecutor and an AsyncConfigurer wrapping your
custom Executor.
The auto-configured TaskExecutorBuilder allows you to easily create instances
that reproduce what the auto-configuration does by default.
The thread pool uses 8 core threads that can grow and shrink according to the
load. Those default settings can be fine-tuned using
the spring.task.execution namespace as shown in the following example:
spring.task.execution.pool.max-threads=16
spring.task.execution.pool.queue-capacity=100
spring.task.execution.pool.keep-alive=10s
This changes the thread pool to use a bounded queue so that when the queue
is full (100 tasks), the thread pool increases to maximum 16 threads.
Shrinking of the pool is more aggressive as threads are reclaimed when they
are idle for 10 seconds (rather than 60 seconds by default).
Integration
Spring Boot offers several conveniences for working with Spring Integration,
including the spring-boot-starter-integration “Starter”. Spring Integration
provides abstractions over messaging and also other transports such as
HTTP, TCP, and others. If Spring Integration is available on your classpath, it
is initialized through the @EnableIntegration annotation.
Spring Boot also configures some features that are triggered by the presence
of additional Spring Integration modules. If spring-integration-jmx is also on
the classpath, message processing statistics are published over JMX .
If spring-integration-jdbc is available, the default database schema can be
created on startup, as shown in the following line:
spring.integration.jdbc.initialize-schema=always
JDBC
Redis
Hazelcast
MongoDB
When building a reactive web application, the following stores can be auto-
configured:
Redis
MongoDB
spring.session.store-type=jdbc
If your platform provides a standard MBeanServer , Spring Boot will use that
and default to the VM MBeanServer if necessary. If all that fails, a
new MBeanServer will be created.
46. Testing
Spring Boot provides a number of utilities and annotations to help when
testing your application. Test support is provided by two modules: spring-
boot-test contains core items, and spring-boot-test-
autoconfigure supports auto-configuration for tests.
If you have not used the spring-test module before, you should start by
reading the relevant section of the Spring Framework reference
documentation.
External properties, logging, and other features of Spring Boot are installed in the
context by default only if you use SpringApplication to create it.
If your test is @Transactional, it rolls back the transaction at the end of each test
method by default. However, as using this arrangement with
either RANDOM_PORT or DEFINED_PORT implicitly provides a real servlet
environment, the HTTP client and server run in separate threads and, thus, in
separate transactions. Any transaction initiated on the server does not roll back in
this case.
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.main.web-application-type=reactive")
public class MyWebFluxTests { ... }
46.3.2 Detecting Test Configuration
If you are familiar with the Spring Test Framework, you may be used to
using @ContextConfiguration(classes=…) in order to specify which
Spring @Configuration to load. Alternatively, you might have often used
nested @Configuration classes within your test.
When testing Spring Boot applications, this is often not required. Spring
Boot’s @*Test annotations search for your primary configuration automatically
whenever you do not explicitly define one.
The search algorithm works up from the package that contains the test until it
finds a class annotated
with @SpringBootApplication or @SpringBootConfiguration . As long as
you structured your code in a sensible way, your main configuration is usually
found.
If you use a test annotation to test a more specific slice of your application, you
should avoid adding configuration settings that are specific to a particular area on
the main method’s application class.
The underlying component scan configuration
of @SpringBootApplication defines exclude filters that are used to make sure
slicing works as expected. If you are using an explicit @ComponentScan directive
on your @SpringBootApplication-annotated class, be aware that those filters
will be disabled. If you are using slicing, you should define them again.
@RunWith(SpringRunner.class)
@SpringBootTest
@Import(MyTestsConfiguration.class)
public class MyTests {
@Test
public void exampleTest() {
...
}
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockM
vc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MockMvcExampleTests {
@Autowired
private MockMvc mvc;
@Test
public void exampleTest() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(content().string("Hello World"));
}
If you want to focus only on the web layer and not start a
complete ApplicationContext, consider using @WebMvcTest instead.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebT
estClient;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWebTestClient
public class MockWebTestClientExampleTests {
@Autowired
private WebTestClient webClient;
@Test
public void exampleTest() {
this.webClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello
World");
}
}
46.3.5 Testing with a running server
If you need to start a full running server, we recommend that you use random
ports. If you
use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) , an
available port is picked at random each time your test runs.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortWebTestClientExampleTests {
@Autowired
private WebTestClient webClient;
@Test
public void exampleTest() {
this.webClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Hello
World");
}
This setup requires spring-webflux on the classpath. If you can’t or won’t add
webflux, Spring Boot also provides a TestRestTemplate facility:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class RandomPortTestRestTemplateExampleTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void exampleTest() {
String body = this.restTemplate.getForObject("/",
String.class);
assertThat(body).isEqualTo("Hello World");
}
}
46.3.6 Using JMX
As the test context framework caches context, JMX is disabled by default to
prevent identical components to register on the same domain. If such test
needs access to an MBeanServer , consider marking it dirty as well:
@RunWith(SpringRunner.class)
@SpringBootTest(properties = "spring.jmx.enabled=true")
@DirtiesContext
public class SampleJmxTests {
@Autowired
private MBeanServer mBeanServer;
@Test
public void exampleTest() {
// ...
}
}
46.3.7 Mocking and Spying Beans
When running tests, it is sometimes necessary to mock certain components
within your application context. For example, you may have a facade over
some remote service that is unavailable during development. Mocking can
also be useful when you want to simulate failures that might be hard to trigger
in a real environment.
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*;
import org.springframework.test.context.junit4.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {
@MockBean
private RemoteService remoteService;
@Autowired
private Reverser reverser;
@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}
@MockBean cannot be used to mock the behavior of a bean that’s exercised during
application context refresh. By the time the test is executed, the application context
refresh has completed and it is too late to configure the mocked behavior. We
recommend using a @Bean method to create and configure the mock in this
situation.
Additionally, you can use @SpyBean to wrap any existing bean with a
Mockito spy . See the Javadoc for full details.
While Spring’s test framework caches application contexts between tests and reuses
a context for tests sharing the same configuration, the use
of @MockBean or @SpyBean influences the cache key, which will most likely
increase the number of contexts.
If you are using @SpyBean to spy on a bean with @Cacheable methods that refer
to parameters by name, your application must be compiled with -parameters.
This ensures that the parameter names are available to the caching infrastructure
once the bean has been spied upon.
46.3.8 Auto-configured Tests
Spring Boot’s auto-configuration system works well for applications but can
sometimes be a little too much for tests. It often helps to load only the parts of
the configuration that are required to test a “slice” of your application. For
example, you might want to test that Spring MVC controllers are mapping
URLs correctly, and you do not want to involve database calls in those tests,
or you might want to test JPA entities, and you are not interested in the web
layer when those tests run.
Each slice restricts component scan to appropriate components and loads a very
restricted set of auto-configuration classes. If you need to exclude one of them,
most @…Test annotations provide an excludeAutoConfiguration attribute.
Alternatively, you can use @ImportAutoConfiguration#exclude.
Including multiple “slices” by using several @…Test annotations in one test is not
supported. If you need multiple “slices”, pick one of the @…Testannotations and
include the @AutoConfigure… annotations of the other “slices” by hand.
A list of the auto-configurations that are enabled by @JsonTest can be found in the
appendix.
Spring Boot includes AssertJ-based helpers that work with the JSONAssert
and JsonPath libraries to check that JSON appears as expected.
The JacksonTester , GsonTester , JsonbTester , and BasicJsonTester classes
can be used for Jackson, Gson, Jsonb, and Strings respectively. Any helper
fields on the test class can be @Autowired when using @JsonTest . The
following example shows a test class for Jackson:
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.json.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.json.*;
import org.springframework.test.context.junit4.*;
@RunWith(SpringRunner.class)
@JsonTest
public class MyJsonTests {
@Autowired
private JacksonTester<VehicleDetails> json;
@Test
public void testSerialize() throws Exception {
VehicleDetails details = new VehicleDetails("Honda",
"Civic");
// Assert against a `.json` file in the same package as the
test
assertThat(this.json.write(details)).isEqualToJson("expected.json"
);
// Or use JSON path based assertions
assertThat(this.json.write(details)).hasJsonPathStringValue("@.mak
e");
assertThat(this.json.write(details)).extractingJsonPathStringValue
("@.make")
.isEqualTo("Honda");
}
@Test
public void testDeserialize() throws Exception {
String content = "{\"make\":\"Ford\",\"model\":\"Focus\"}";
assertThat(this.json.parse(content))
.isEqualTo(new VehicleDetails("Ford",
"Focus"));
assertThat(this.json.parseObject(content).getMake()).isEqualTo("Fo
rd");
}
JSON helper classes can also be used directly in standard unit tests. To do so, call
the initFields method of the helper in your @Before method if you do not
use @JsonTest.
assertThat(json.write(message))
.extractingJsonPathNumberValue("@.test.numberValue")
.satisfies((number) ->
assertThat(number.floatValue()).isCloseTo(0.15f, within(0.01f)));
46.3.10 Auto-configured Spring MVC Tests
To test whether Spring MVC controllers are working as expected, use
the @WebMvcTest annotation. @WebMvcTest auto-configures the Spring MVC
infrastructure and limits scanned beans
to @Controller , @ControllerAdvice , @JsonComponent , Converter , GenericCon
verter , Filter , WebMvcConfigurer , and HandlerMethodArgumentResolver .
Regular @Component beans are not scanned when using this annotation.
If you need to register extra components, such as the Jackson Module, you can
import additional configuration classes by using @Import on your test.
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;
@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests {
@Autowired
private MockMvc mvc;
@MockBean
private UserVehicleService userVehicleService;
@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda",
"Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN
))
.andExpect(status().isOk()).andExpect(content().string("Honda
Civic"));
}
@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyHtmlUnitTests {
@Autowired
private WebClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda",
"Civic"));
HtmlPage page =
this.webClient.getPage("/sboot/vehicle.html");
assertThat(page.getBody().getTextContent()).isEqualTo("Honda
Civic");
}
By default, Spring Boot puts WebDriver beans in a special “scope” to ensure that
the driver exits after each test and that a new instance is injected. If you do not want
this behavior, you can add @Scope("singleton") to
your WebDriver @Bean definition.
The webDriver scope created by Spring Boot will replace any user defined scope
of the same name. If you define your own webDriver scope you may find it stops
working when you use @WebMvcTest.
Sometimes writing Spring MVC tests is not enough; Spring Boot can help you
run full end-to-end tests with an actual server.
46.3.11 Auto-configured Spring WebFlux Tests
To test that Spring WebFlux controllers are working as expected, you can use
the @WebFluxTest annotation. @WebFluxTest auto-configures the Spring
WebFlux infrastructure and limits scanned beans
to @Controller , @ControllerAdvice , @JsonComponent , Converter , GenericCon
verter , and WebFluxConfigurer . Regular @Component beans are not scanned
when the @WebFluxTest annotation is used.
If you need to register extra components, such as Jackson Module, you can import
additional configuration classes using @Import on your test.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@WebFluxTest(UserVehicleController.class)
public class MyControllerTests {
@Autowired
private WebTestClient webClient;
@MockBean
private UserVehicleService userVehicleService;
@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda",
"Civic"));
this.webClient.get().uri("/sboot/vehicle").accept(MediaType.TEXT_P
LAIN)
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("Honda
Civic");
}
}
This setup is only supported by WebFlux applications as using WebTestClient in
a mocked web application only works with WebFlux at the moment.
@WebFluxTest cannot detect routes registered via the functional web framework.
For testing RouterFunction beans in the context, consider importing
your RouterFunction yourself via @Import or using @SpringBootTest.
Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help you
run full end-to-end tests with an actual server.
46.3.12 Auto-configured Data JPA Tests
You can use the @DataJpaTest annotation to test JPA applications. By default,
it configures an in-memory embedded database, scans for @Entity classes,
and configures Spring Data JPA repositories. Regular @Component beans are
not loaded into the ApplicationContext .
By default, data JPA tests are transactional and roll back at the end of each
test. See the relevant section in the Spring Framework Reference
Documentation for more details. If that is not what you want, you can disable
transaction management for a test or for the whole class as follows:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {
Data JPA tests may also inject a TestEntityManager bean, which provides an
alternative to the standard JPA EntityManager that is specifically designed for
tests. If you want to use TestEntityManager outside
of @DataJpaTest instances, you can also use
the @AutoConfigureTestEntityManager annotation. A JdbcTemplate is also
available if you need that. The following example shows
the @DataJpaTest annotation in use:
import org.junit.*;
import org.junit.runner.*;
import org.springframework.boot.test.autoconfigure.orm.jpa.*;
@RunWith(SpringRunner.class)
@DataJpaTest
public class ExampleRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
public void testExample() throws Exception {
this.entityManager.persist(new User("sboot", "1234"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("1234");
}
}
In-memory embedded databases generally work well for tests, since they are
fast and do not require any installation. If, however, you prefer to run tests
against a real database you can use
the @AutoConfigureTestDatabase annotation, as shown in the following
example:
@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace=Replace.NONE)
public class ExampleRepositoryTests {
// ...
}
46.3.13 Auto-configured JDBC Tests
@JdbcTest is similar to @DataJpaTest but is for tests that only require
a DataSource and do not use Spring Data JDBC. By default, it configures an
in-memory embedded database and a JdbcTemplate .
Regular @Component beans are not loaded into the ApplicationContext .
A list of the auto-configurations that are enabled by @JdbcTest can be found in the
appendix.
By default, JDBC tests are transactional and roll back at the end of each test.
See the relevant section in the Spring Framework Reference Documentation
for more details. If that is not what you want, you can disable transaction
management for a test or for the whole class, as follows:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringRunner.class)
@JdbcTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {
If you prefer your test to run against a real database, you can use
the @AutoConfigureTestDatabase annotation in the same way as
for DataJpaTest . (See "Section 46.3.12, “Auto-configured Data JPA Tests”".)
By default, Data JDBC tests are transactional and roll back at the end of each
test. See the relevant section in the Spring Framework Reference
Documentation for more details. If that is not what you want, you can disable
transaction management for a test or for the whole test class as shown in the
JDBC example.
If you prefer your test to run against a real database, you can use
the @AutoConfigureTestDatabase annotation in the same way as
for DataJpaTest . (See "Section 46.3.12, “Auto-configured Data JPA Tests”".)
import org.jooq.DSLContext;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.jooq.JooqTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@JooqTest
public class ExampleJooqTests {
@Autowired
private DSLContext dslContext;
}
JOOQ tests are transactional and roll back at the end of each test by default.
If that is not what you want, you can disable transaction management for a
test or for the whole test class as shown in the JDBC example.
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataMongoTest
public class ExampleDataMongoTests {
@Autowired
private MongoTemplate mongoTemplate;
//
}
In-memory embedded MongoDB generally works well for tests, since it is fast
and does not require any developer installation. If, however, you prefer to run
tests against a real MongoDB server, you should exclude the embedded
MongoDB auto-configuration, as shown in the following example:
import org.junit.runner.RunWith;
import
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoCon
figuration;
import
org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataMongoTest(excludeAutoConfiguration =
EmbeddedMongoAutoConfiguration.class)
public class ExampleDataMongoNonEmbeddedTests {
}
46.3.17 Auto-configured Data Neo4j Tests
You can use @DataNeo4jTest to test Neo4j applications. By default, it uses an
in-memory embedded Neo4j (if the embedded driver is available), scans
for @NodeEntity classes, and configures Spring Data Neo4j repositories.
Regular @Component beans are not loaded into the ApplicationContext . (For
more about using Neo4J with Spring Boot, see "Section 32.3, “Neo4j”", earlier
in this chapter.)
The following example shows a typical setup for using Neo4J tests in Spring
Boot:
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataNeo4jTest
public class ExampleDataNeo4jTests {
@Autowired
private YourRepository repository;
//
}
By default, Data Neo4j tests are transactional and roll back at the end of each
test. See the relevant section in the Spring Framework Reference
Documentation for more details. If that is not what you want, you can disable
transaction management for a test or for the whole class, as follows:
import org.junit.Test;
import org.junit.runner.RunWith;
import
org.springframework.boot.test.autoconfigure.data.neo4j.DataNeo4jTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@RunWith(SpringRunner.class)
@DataNeo4jTest
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public class ExampleNonTransactionalTests {
}
46.3.18 Auto-configured Data Redis Tests
You can use @DataRedisTest to test Redis applications. By default, it scans
for @RedisHash classes and configures Spring Data Redis repositories.
Regular @Component beans are not loaded into the ApplicationContext . (For
more about using Redis with Spring Boot, see "Section 32.1, “Redis”", earlier
in this chapter.)
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataRedisTest
public class ExampleDataRedisTests {
@Autowired
private YourRepository repository;
//
}
46.3.19 Auto-configured Data LDAP Tests
You can use @DataLdapTest to test LDAP applications. By default, it
configures an in-memory embedded LDAP (if available), configures
an LdapTemplate , scans for @Entry classes, and configures Spring Data
LDAP repositories. Regular @Component beans are not loaded into
the ApplicationContext . (For more about using LDAP with Spring Boot, see
"Section 32.9, “LDAP”", earlier in this chapter.)
A list of the auto-configuration settings that are enabled by @DataLdapTest can
be found in the appendix.
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataLdapTest
public class ExampleDataLdapTests {
@Autowired
private LdapTemplate ldapTemplate;
//
}
In-memory embedded LDAP generally works well for tests, since it is fast and
does not require any developer installation. If, however, you prefer to run tests
against a real LDAP server, you should exclude the embedded LDAP auto-
configuration, as shown in the following example:
import org.junit.runner.RunWith;
import
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfi
guration;
import org.springframework.boot.test.autoconfigure.data.ldap.DataLdapTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@DataLdapTest(excludeAutoConfiguration =
EmbeddedLdapAutoConfiguration.class)
public class ExampleDataLdapNonEmbeddedTests {
}
46.3.20 Auto-configured REST Clients
You can use the @RestClientTest annotation to test REST clients. By default,
it auto-configures Jackson, GSON, and Jsonb support, configures
a RestTemplateBuilder , and adds support for MockRestServiceServer .
Regular @Component beans are not loaded into the ApplicationContext .
The specific beans that you want to test should be specified by using
the value or components attribute of @RestClientTest , as shown in the
following example:
@RunWith(SpringRunner.class)
@RestClientTest(RemoteVehicleDetailsService.class)
public class ExampleRestClientTest {
@Autowired
private RemoteVehicleDetailsService service;
@Autowired
private MockRestServiceServer server;
@Test
public void
getVehicleDetailsWhenResultIsSuccessShouldReturnDetails()
throws Exception {
this.server.expect(requestTo("/greet/details"))
.andRespond(withSuccess("hello",
MediaType.TEXT_PLAIN));
String greeting = this.service.callRestService();
assertThat(greeting).isEqualTo("hello");
}
}
46.3.21 Auto-configured Spring REST Docs Tests
You can use the @AutoConfigureRestDocs annotation to use Spring REST
Docs in your tests with Mock MVC, REST Assured, or WebTestClient. It
removes the need for the JUnit rule in Spring REST Docs.
@AutoConfigureRestDocs can be used to override the default output directory
( target/generated-snippets if you are using Maven or build/generated-
snippets if you are using Gradle). It can also be used to configure the host,
scheme, and port that appears in any documented URIs.
Auto-configured Spring REST Docs Tests with Mock MVC
@AutoConfigureRestDocs customizes the MockMvc bean to use Spring REST
Docs. You can inject it by using @Autowired and use it in your tests as you
normally would when using Mock MVC and Spring REST Docs, as shown in
the following example:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static
org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
@AutoConfigureRestDocs
public class UserDocumentationTests {
@Autowired
private MockMvc mvc;
@Test
public void listUsers() throws Exception {
this.mvc.perform(get("/users").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andDo(document("list-users"));
}
}
If you require more control over Spring REST Docs configuration than offered
by the attributes of @AutoConfigureRestDocs , you can use
a RestDocsMockMvcConfigurationCustomizer bean, as shown in the following
example:
@TestConfiguration
static class CustomizationConfiguration
implements RestDocsMockMvcConfigurationCustomizer {
@Override
public void customize(MockMvcRestDocumentationConfigurer
configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown(
));
}
If you want to make use of Spring REST Docs support for a parameterized
output directory, you can create a RestDocumentationResultHandler bean.
The auto-configuration calls alwaysDo with this result handler, thereby causing
each MockMvc call to automatically generate the default snippets. The
following example shows a RestDocumentationResultHandler being defined:
@TestConfiguration
static class ResultHandlerConfiguration {
@Bean
public RestDocumentationResultHandler restDocumentation() {
return MockMvcRestDocumentation.document("{method-name}");
}
}
Auto-configured Spring REST Docs Tests with WebTestClient
@AutoConfigureRestDocs can also be used with WebTestClient . You can inject
it by using @Autowired and use it in your tests as you normally would when
using @WebFluxTest and Spring REST Docs, as shown in the following
example:
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
;
import
org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
import static
org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.
document;
@RunWith(SpringRunner.class)
@WebFluxTest
@AutoConfigureRestDocs
public class UsersDocumentationTests {
@Autowired
private WebTestClient webTestClient;
@Test
void listUsers() {
this.webTestClient.get().uri("/").exchange().expectStatus().isOk()
.expectBody()
.consumeWith(document("list-users"));
}
If you require more control over Spring REST Docs configuration than offered
by the attributes of @AutoConfigureRestDocs , you can use
a RestDocsWebTestClientConfigurationCustomizer bean, as shown in the
following example:
@TestConfiguration
public static class CustomizationConfiguration
implements RestDocsWebTestClientConfigurationCustomizer {
@Override
public void customize(WebTestClientRestDocumentationConfigurer
configurer) {
configurer.snippets().withEncoding("UTF-8");
}
}
Auto-configured Spring REST Docs Tests with REST Assured
@AutoConfigureRestDocs makes a RequestSpecification bean, preconfigured
to use Spring REST Docs, available to your tests. You can inject it by
using @Autowired and use it in your tests as you normally would when using
REST Assured and Spring REST Docs, as shown in the following example:
import io.restassured.specification.RequestSpecification;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs
;
import org.springframework.boot.test.context.SpringBootTest;
import
org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureRestDocs
public class UserDocumentationTests {
@LocalServerPort
private int port;
@Autowired
private RequestSpecification documentationSpec;
@Test
public void listUsers() {
given(this.documentationSpec).filter(document("list-
users")).when()
.port(this.port).get("/").then().assertThat().statusCode(is(200));
}
If you require more control over Spring REST Docs configuration than offered
by the attributes of @AutoConfigureRestDocs ,
a RestDocsRestAssuredConfigurationCustomizer bean can be used, as shown
in the following example:
@TestConfiguration
public static class CustomizationConfiguration
implements RestDocsRestAssuredConfigurationCustomizer {
@Override
public void customize(RestAssuredRestDocumentationConfigurer
configurer) {
configurer.snippets().withTemplateFormat(TemplateFormats.markdown(
));
}
}
46.3.22 Additional Auto-configuration and Slicing
Each slice provides one or more @AutoConfigure… annotations that namely
defines the auto-configurations that should be included as part of a slice.
Additional auto-configurations can be added by creating a
custom @AutoConfigure… annotation or simply by
adding @ImportAutoConfiguration to the test as shown in the following
example:
@RunWith(SpringRunner.class)
@JdbcTest
@ImportAutoConfiguration(IntegrationAutoConfiguration.class)
public class ExampleJdbcTests {
Make sure to not use the regular @Import annotation to import auto-configurations
as they are handled in a specific way by Spring Boot.
46.3.23 User Configuration and Slicing
If you structure your code in a sensible way,
your @SpringBootApplication class is used by default as the configuration of
your tests.
It then becomes important not to litter the application’s main class with
configuration settings that are specific to a particular area of its functionality.
Assume that you are using Spring Batch and you rely on the auto-
configuration for it. You could define your @SpringBootApplication as follows:
@SpringBootApplication
@EnableBatchProcessing
public class SampleApplication { ... }
Because this class is the source configuration for the test, any slice test
actually tries to start Spring Batch, which is definitely not what you want to do.
A recommended approach is to move that area-specific configuration to a
separate @Configuration class at the same level as your application, as
shown in the following example:
@Configuration
@EnableBatchProcessing
public class BatchConfiguration { ... }
Test slices exclude @Configuration classes from scanning. For example, for
a @WebMvcTest , the following configuration will not include the
given WebMvcConfigurer bean in the application context loaded by the test
slice:
@Configuration
public class WebConfiguration {
@Bean
public WebMvcConfigurer testConfigurer() {
return new WebMvcConfigurer() {
...
};
}
}
@Component
public class TestWebMvcConfigurer extends WebMvcConfigurer {
...
}
@SpringBootApplication
@ComponentScan({ "com.example.app", "org.acme.another" })
public class SampleApplication { ... }
Doing so effectively overrides the default component scan directive with the
side effect of scanning those two packages regardless of the slice that you
chose. For instance, a @DataJpaTest seems to suddenly scan components
and user configurations of your application. Again, moving the custom
directive to a separate class is a good way to fix this issue.
46.4.1 ConfigFileApplicationContextInitializer
ConfigFileApplicationContextInitializer is
an ApplicationContextInitializer that you can apply to your tests to load
Spring Boot application.properties files. You can use it when you do not
need the full set of features provided by @SpringBootTest , as shown in the
following example:
@ContextConfiguration(classes = Config.class,
initializers = ConfigFileApplicationContextInitializer.class)
TestPropertyValues.of("org=Spring", "name=Boot").applyTo(env);
46.4.3 OutputCapture
OutputCapture is a JUnit Rule that you can use to
capture System.out and System.err output. You can declare the capture as
a @Rule and then use toString() for assertions, as follows:
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.test.rule.OutputCapture;
@Rule
public OutputCapture capture = new OutputCapture();
@Test
public void testName() throws Exception {
System.out.println("Hello World!");
assertThat(capture.toString(), containsString("World"));
}
}
46.4.4 TestRestTemplate
Spring Framework 5.0 provides a new WebTestClient that works for WebFlux
integration tests and both WebFlux and MVC end-to-end testing. It provides a fluent
API for assertions, unlike TestRestTemplate.
Redirects are not followed (so you can assert the response location).
Cookies are ignored (so the template is stateless).
assertThat(headers.getLocation()).hasHost("other.example.com");
}
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleWebClientTests {
@Autowired
private TestRestTemplate template;
@Test
public void testRequest() {
HttpHeaders headers =
this.template.getForEntity("/example", String.class)
.getHeaders();
assertThat(headers.getLocation()).hasHost("other.example.com");
}
@TestConfiguration
static class Config {
@Bean
public RestTemplateBuilder restTemplateBuilder() {
return new
RestTemplateBuilder().setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(1));
}
}
47. WebSockets
Spring Boot provides WebSockets auto-configuration for embedded Tomcat,
Jetty, and Undertow. If you deploy a war file to a standalone container, Spring
Boot assumes that the container is responsible for the configuration of its
WebSocket support.
Spring Framework provides rich WebSocket support for MVC web
applications that can be easily accessed through the spring-boot-starter-
websocket module.
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>
The Spring Web Services features can be easily accessed with the spring-
boot-starter-webservices module.
@Service
public class MyService {
public MyService(WebServiceTemplateBuilder
webServiceTemplateBuilder) {
this.webServiceTemplate =
webServiceTemplateBuilder.build();
}
@Bean
public WebServiceTemplate webServiceTemplate(WebServiceTemplateBuilder
builder) {
return builder.messageSenders(new
HttpWebServiceMessageSenderBuilder()
.setConnectTimeout(5000).setReadTimeout(2000).build()).build();
A demo project is available to showcase how you can create a starter step-by-step.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.mycorp.libx.autoconfigure.LibXAutoConfiguration,\
com.mycorp.libx.autoconfigure.LibXWebAutoConfiguration
Auto-configurations must be loaded that way only. Make sure that they are defined
in a specific package space and that they are never the target of component
scanning. Furthermore, auto-configuration classes should not enable component
scanning to find additional components. Specific @Imports should be used instead.
If you want to order certain auto-configurations that should not have any direct
knowledge of each other, you can also use @AutoConfigureOrder . That
annotation has the same semantic as the regular @Order annotation but
provides a dedicated order for auto-configuration classes.
This mechanism does not apply the same way to @Bean methods where
typically the return type is the target of the condition: before the condition on
the method applies, the JVM will have loaded the class and potentially
processed method references which will fail if the class is not present.
@Configuration
// Some conditions
public class MyAutoConfiguration {
// Auto-configured beans
@Configuration
@ConditionalOnClass(EmbeddedAcmeService.class)
static class EmbeddedConfiguration {
@Bean
@ConditionalOnMissingBean
public EmbeddedAcmeService embeddedAcmeService() { ... }
When placed on a @Bean method, the target type defaults to the return type of
the method, as shown in the following example:
@Configuration
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() { ... }
You need to be very careful about the order in which bean definitions are added, as
these conditions are evaluated based on what has been processed so far. For this
reason, we recommend using
only @ConditionalOnBean and @ConditionalOnMissingBean annotations on
auto-configuration classes (since these are guaranteed to load after any user-defined
bean definitions have been added).
.withConfiguration(AutoConfigurations.of(UserServiceAutoConfigurat
ion.class));
Each test can use the runner to represent a particular use case. For instance,
the sample below invokes a user configuration ( UserConfiguration ) and
checks that the auto-configuration backs off properly. Invoking run provides a
callback context that can be used with Assert4J .
@Test
public void defaultServiceBacksOff() {
this.contextRunner.withUserConfiguration(UserConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class)).isSameAs(
context.getBean(UserConfiguration.class).myUserService());
});
}
@Configuration
static class UserConfiguration {
@Bean
public UserService myUserService() {
return new UserService("mine");
}
@Test
public void serviceNameCanBeConfigured() {
this.contextRunner.withPropertyValues("user.name=test123").run((co
ntext) -> {
assertThat(context).hasSingleBean(UserService.class);
assertThat(context.getBean(UserService.class).getName()).isEqualTo
("test123");
});
}
@Test
public void autoConfigTest {
ConditionEvaluationReportLoggingListener initializer = new
ConditionEvaluationReportLoggingListener(
LogLevel.INFO);
ApplicationContextRunner contextRunner = new
ApplicationContextRunner()
.withInitializer(initializer).run((context) -> {
// Do something...
});
}
49.4.1 Simulating a Web Context
If you need to test an auto-configuration that only operates in a Servlet or
Reactive web application context, use
the WebApplicationContextRunner or ReactiveWebApplicationContextRunner r
espectively.
@Test
public void serviceIsIgnoredIfLibraryIsNotPresent() {
this.contextRunner.withClassLoader(new
FilteredClassLoader(UserService.class))
.run((context) ->
assertThat(context).doesNotHaveBean("userService"));
}
You may combine the auto-configuration code and the dependency management in
a single module if you do not need to separate those two concerns.
49.5.1 Naming
You should make sure to provide a proper namespace for your starter. Do not
start your module names with spring-boot , even if you use a different
Maven groupId . We may offer official support for the thing you auto-configure
in the future.
As a rule of thumb, you should name a combined module after the starter. For
example, assume that you are creating a starter for "acme" and that you name
the auto-configure module acme-spring-boot-autoconfigure and the
starter acme-spring-boot-starter . If you only have one module that
combines the two, name it acme-spring-boot-starter .
Also, if your starter provides configuration keys, use a unique namespace for
them. In particular, do not include your keys in the namespaces that Spring
Boot uses (such as server , management , spring , and so on). If you use the
same namespace, we may modify these namespaces in the future in ways
that break your modules.
Make sure to trigger meta-data generation so that IDE assistance is available
for your keys as well. You may want to review the generated meta-data
( META-INF/spring-configuration-metadata.json ) to make sure your keys are
properly documented.
You should mark the dependencies to the library as optional so that you can include
the autoconfigure module in your projects more easily. If you do it that way, the
library is not provided and, by default, Spring Boot backs off.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
dependencies {
compileOnly "org.springframework.boot:spring-boot-autoconfigure-
processor"
}
dependencies {
annotationProcessor "org.springframework.boot:spring-boot-
autoconfigure-processor"
}
49.5.3 Starter Module
The starter is really an empty jar. Its only purpose is to provide the necessary
dependencies to work with the library. You can think of it as an opinionated
view of what is required to get started.
Do not make assumptions about the project in which your starter is added. If
the library you are auto-configuring typically requires other starters, mention
them as well. Providing a proper set of default dependencies may be hard if
the number of optional dependencies is high, as you should avoid including
dependencies that are unnecessary for a typical usage of the library. In other
words, you should not include optional dependencies.
Either way, your starter must reference the core Spring Boot starter (spring-boot-
starter) directly or indirectly (i.e. no need to add it if your starter relies on another
starter). If a project is created with only your custom starter, Spring Boot’s core features
will be honoured by the presence of the core starter.
50.1 Requirements
Spring Boot supports Kotlin 1.2.x. To use
Kotlin, org.jetbrains.kotlin:kotlin-
stdlib and org.jetbrains.kotlin:kotlin-reflect must be present
on the classpath. The kotlin-stdlib variants kotlin-stdlib-
jdk7 and kotlin-stdlib-jdk8 can also be used.
Since Kotlin classes are final by default, you are likely to want to
configure kotlin-spring plugin in order to automatically open Spring-
annotated classes so that they can be proxied.
Jackson’s Kotlin module is required for serializing / deserializing JSON
data in Kotlin. It is automatically registered when found on the
classpath. A warning message is logged if Jackson and Kotlin are
present but the Jackson Kotlin module is not.
50.2 Null-safety
One of Kotlin’s key features is null-safety. It deals with null values at
compile time rather than deferring the problem to runtime and
encountering a NullPointerException . This helps to eliminate a
common source of bugs without paying the cost of wrappers
like Optional . Kotlin also allows using functional constructs with
nullable values as described in this comprehensive guide to null-safety
in Kotlin.
Although Java does not allow one to express null-safety in its type
system, Spring Framework, Spring Data, and Reactor now provide
null-safety of their API via tooling-friendly annotations. By default,
types from Java APIs used in Kotlin are recognized as platform
types for which null-checks are relaxed. Kotlin’s support for JSR 305
annotations combined with nullability annotations provide null-safety
for the related Spring API in Kotlin.
Generic type arguments, varargs and array elements nullability are not yet
supported. See SPR-15942 for up-to-date information. Also be aware that
Spring Boot’s own API is not yet annotated.
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
kotlin-reflect
kotlin-runtime
kotlin-stdlib
kotlin-stdlib-jdk7
kotlin-stdlib-jdk8
kotlin-stdlib-jre7
kotlin-stdlib-jre8
50.5 @ConfigurationProperties
@ConfigurationProperties currently only works with lateinit or
nullable var properties (the former is recommended), since immutable
classes initialized by constructors are not yet supported.
@ConfigurationProperties("example.kotlin")
class KotlinExampleProperties {
class MyService {
50.6 Testing
While it is possible to use JUnit 4 (the default provided by spring-
boot-starter-test ) to test Kotlin code, JUnit 5 is recommended. JUnit
5 enables a test class to be instantiated once and reused for all of the
class’s tests. This makes it possible to
use @BeforeAll and @AfterAll annotations on non-static methods,
which is a good fit for Kotlin.
50.7 Resources
50.7.1 Further reading
50.7.2 Examples