The Spring Boot auto-configuration tries its best to ‘do the right thing’, but sometimes things fail and it can be hard to tell why.
There is a really useful AutoConfigurationReport
available in any Spring Boot
ApplicationContext
. You will see it if you enable DEBUG
logging output. If you use
the spring-boot-actuator
there is also an autoconfig
endpoint that renders the report
in JSON. Use that to debug the application and see what features have been added (and
which not) by Spring Boot at runtime.
Many more questions can be answered by looking at the source code and the javadoc. Some rules of thumb:
-
Look for classes called
*AutoConfiguration
and read their sources, in particular the@Conditional*
annotations to find out what features they enable and when. Add--debug
to the command line or a System property-Ddebug
to get a log on the console of all the autoconfiguration decisions that were made in your app. In a running Actuator app look at theautoconfig
endpoint (`/autoconfig' or the JMX equivalent) for the same information. -
Look for classes that are
@ConfigurationProperties
(e.g. {sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[ServerProperties
]) and read from there the available external configuration options. The@ConfigurationProperties
has aname
attribute which acts as a prefix to external properties, thusServerProperties
hasprefix="server"
and its configuration properties areserver.port
,server.address
etc. In a running Actuator app look at theconfigprops
endpoint. -
Look for use of
RelaxedEnvironment
to pull configuration values explicitly out of theEnvironment
. It often is used with a prefix. -
Look for
@Value
annotations that bind directly to theEnvironment
. This is less flexible than theRelaxedEnvironment
approach, but does allow some relaxed binding, specifically for OS environment variables (soCAPITALS_AND_UNDERSCORES
are synonyms forperiod.separated
). -
Look for
@ConditionalOnExpression
annotations that switch features on and off in response to SpEL expressions, normally evaluated with place-holders resolved from theEnvironment
.
A SpringApplication
has ApplicationListeners
and ApplicationContextInitializers
that
are used to apply customizations to the context or environment. Spring Boot loads a number
of such customizations for use internally from META-INF/spring.factories
. There is more
than one way to register additional ones:
-
Programmatically per application by calling the
addListeners
andaddInitializers
methods onSpringApplication
before you run it. -
Declaratively per application by setting
context.initializer.classes
orcontext.listener.classes
. -
Declaratively for all applications by adding a
META-INF/spring.factories
and packaging a jar file that the applications all use as a library.
The SpringApplication
sends some special ApplicationEvents
to the listeners (even
some before the context is created), and then registers the listeners for events published
by the ApplicationContext
as well. See
'spring-boot-features.adoc' in the
‘Spring Boot features’ section for a complete list.
You can use the ApplicationBuilder
class to create parent/child ApplicationContext
hierarchies. See 'spring-boot-features.adoc'
in the ‘Spring Boot features’ section for more information.
Not all Spring applications have to be web applications (or web services). If you want to
execute some code in a main
method, but also bootstrap a Spring application to set up
the infrastructure to use, then it’s easy with the SpringApplication
features of Spring
Boot. A SpringApplication
changes its ApplicationContext
class depending on whether it
thinks it needs a web application or not. The first thing you can do to help it is to just
leave the servlet API dependencies off the classpath. If you can’t do that (e.g. you are
running 2 applications from the same code base) then you can explicitly call
SpringApplication.setWebEnvironment(false)
, or set the applicationContextClass
property (through the Java API or with external properties).
Application code that you want to run as your business logic can be implemented as a
CommandLineRunner
and dropped into the context as a @Bean
definition.
A SpringApplication
has bean properties (mainly setters) so you can use its Java API as
you create the application to modify its behavior. Or you can externalize the
configuration using properties in spring.main.*
. E.g. in application.properties
you
might have.
spring.main.web_environment=false
spring.main.show_banner=false
and then the Spring Boot banner will not be printed on startup, and the application will not be a web application.
Note
|
The example above also demonstrates how flexible binding allows the use of
underscores (_ ) as well as dashes (- ) in property names.
|
By default properties from different sources are added to the Spring Environment
in a
defined order (see 'spring-boot-features.adoc' in
the ‘Spring Boot features’ section for the exact order).
A nice way to augment and modify this is to add @PropertySource
annotations to your
application sources. Classes passed to the SpringApplication
static convenience
methods, and those added using setSources()
are inspected to see if they have
@PropertySources
, and if they do, those properties are added to the Environment
early
enough to be used in all phases of the ApplicationContext
lifecycle. Properties added
in this way have precedence over any added using the default locations, but have lower
priority than system properties, environment variables or the command line.
You can also provide System properties (or environment variables) to change the behavior:
-
spring.config.name
(SPRING_CONFIG_NAME
), defaults toapplication
as the root of the file name. -
spring.config.location
(SPRING_CONFIG_LOCATION
) is the file to load (e.g. a classpath resource or a URL). A separateEnvironment
property source is set up for this document and it can be overridden by system properties, environment variables or the command line.
No matter what you set in the environment, Spring Boot will always load
application.properties
as described above. If YAML is used then files with the ‘.yml’
extension are also added to the list by default.
See {sc-spring-boot}/context/config/ConfigFileApplicationListener.{sc-ext}[ConfigFileApplicationListener
]
for more detail.
Some people like to use (for example) --port=9000
instead of --server.port=9000
to
set configuration properties on the command line. You can easily enable this by using
placeholders in application.properties
, e.g.
server.port=${port:8080}
Tip
|
If you are inheriting from the spring-boot-starter-parent POM, or if have enabled
maven filtering for the application.properties directly, you may want to change the
default filter token from ${*} since it conflicts with those placeholders.
You can either use @*@ (i.e. @maven.token@ instead of ${maven.token} ) or you can
configure the maven-resources-plugin to use
other delimiters.
|
Note
|
In this specific case the port binding will work in a PaaS environment like Heroku
and Cloud Foundry, since in those two platforms the PORT environment variable is set
automatically and Spring can bind to capitalized synonyms for Environment properties.
|
YAML is a superset of JSON and as such is a very convenient syntax for storing external properties in a hierarchical format. E.g.
spring:
application:
name: cruncher
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/test
server:
port: 9000
Create a file called application.yml
and stick it in the root of your classpath, and
also add snakeyaml
to your dependencies (Maven coordinates org.yaml:snakeyaml
, already
included if you use the spring-boot-starter
). A YAML file is parsed to a Java
Map<String,Object>
(like a JSON object), and Spring Boot flattens the map so that it
is 1-level deep and has period-separated keys, a lot like people are used to with
Properties
files in Java.
The example YAML above corresponds to an application.properties
file
spring.application.name=cruncher
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
See 'spring-boot-features.adoc' in the ‘Spring Boot features’ section for more information about YAML.
The Spring Environment
has an API for this, but normally you would set a System profile
(spring.profiles.active
) or an OS environment variable (SPRING_PROFILES_ACTIVE
). E.g.
launch your application with a -D
argument (remember to put it before the main class
or jar archive):
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
In Spring Boot you can also set the active profile in application.properties
, e.g.
spring.profiles.active=production
A value set this way is replaced by the System property or environment variable setting,
but not by the SpringApplicationBuilder.profiles()
method. Thus the latter Java API can
be used to augment the profiles without changing the defaults.
See 'spring-boot-features.adoc' in the ‘Spring Boot features’ section for more information.
A YAML file is actually a sequence of documents separated by ---
lines, and each
document is parsed separately to a flattened map.
If a YAML document contains a spring.profiles
key, then the profiles value
(comma-separated list of profiles) is fed into the Spring
Environment.acceptsProfiles()
and if any of those profiles is active that document is
included in the final merge (otherwise not).
Example:
server:
port: 9000
---
spring:
profiles: development
server:
port: 9001
---
spring:
profiles: production
server:
port: 0
In this example the default port is 9000, but if the Spring profile ‘development’ is active then the port is 9001, and if ‘production’ is active then it is 0.
The YAML documents are merged in the order they are encountered (so later values override earlier ones).
To do the same thing with properties files you can use application-${profile}.properties
to specify profile-specific values.
Spring Boot binds external properties from application.properties
(or .yml
) (and
other places) into an application at runtime. There is not (and technically cannot be)
an exhaustive list of all supported properties in a single location because contributions
can come from additional jar files on your classpath.
A running application with the Actuator features has a configprops
endpoint that shows
all the bound and bindable properties available through @ConfigurationProperties
.
The appendix includes an application.properties
example with a list of the most common properties supported by
Spring Boot. The definitive list comes from searching the source code for
@ConfigurationProperties
and @Value
annotations, as well as the occasional use of
RelaxedEnvironment
.
Servlet
, Filter
, ServletContextListener
and the other listeners supported by the
Servlet spec can be added to your application as @Bean
definitions. Be very careful that
they don’t cause eager initialization of too many other beans because they have to be
installed in the container very early in the application lifecycle (e.g. it’s not a good
idea to have them depend on your DataSource
or JPA configuration). You can work around
restrictions like that by initializing them lazily when first used instead of on
initialization.
In the case of Filters
and Servlets
you can also add mappings and init parameters by
adding a FilterRegistrationBean
or ServletRegistrationBean
instead of or as well as
the underlying component.
In a standalone application the main HTTP port defaults to 8080
, but can be set with
server.port
(e.g. in application.properties
or as a System property). Thanks to
relaxed binding of Environment
values you can also use SERVER_PORT
(e.g. as an OS
environment variable).
To switch off the HTTP endpoints completely, but still create a WebApplicationContext
,
use server.port=-1
(this is sometimes useful for testing).
For more details look at 'spring-boot-features.adoc'
in the ‘Spring Boot features’ section, or the
{sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[ServerProperties
] source
code.
To scan for a free port (using OS natives to prevent clashes) use server.port=0
.
You can access the port the server is running on from log output or from the
EmbeddedWebApplicationContext
via its EmbeddedServletContainer
. The best way to get
that and be sure that it has initialized is to add a @Bean
of type
ApplicationListener<EmbeddedServletContainerInitializedEvent>
and pull the container
out of the event when it is published.
A useful practice for use with @IntegrationTest`s is to set `server.port=0
and then inject the actual (‘local’) port as a @Value
. For example:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleDataJpaApplication.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
public class CityRepositoryIntegrationTests {
@Autowired
EmbeddedWebApplicationContext server;
@Value("${local.server.port}")
int port;
// ...
}
SSL can be configured declaratively by setting the various server.ssl.*
properties,
typically in application.properties
or application.yml
. For example:
server.port = 8443
server.ssl.key-store = classpath:keystore.jks
server.ssl.key-store-password = secret
server.ssl.key-password = another-secret
See {sc-spring-boot}/context/embedded/Ssl.{sc-ext}[Ssl
] for details of all of the
supported properties.
Note
|
Tomcat requires the key store (and trust store if you’re using one) to be directly accessible on the filesystem, i.e. it cannot be read from within a jar file. |
Generally you can follow the advice from
'Discover built-in options for external properties' about
@ConfigurationProperties
(ServerProperties
is the main one here), but also look at
EmbeddedServletContainerCustomizer
and various Tomcat-specific *Customizers
that you
can add in one of those. The Tomcat APIs are quite rich so once you have access to the
TomcatEmbeddedServletContainerFactory
you can modify it in a number of ways. Or the
nuclear option is to add your own TomcatEmbeddedServletContainerFactory
.
Add a org.apache.catalina.connector.Connector
to the
TomcatEmbeddedServletContainerFactory
which can allow multiple connectors, e.g. HTTP and
HTTPS connector:
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
File keystore = new ClassPathResource("keystore").getFile();
File truststore = new ClassPathResource("keystore").getFile();
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(keystore.getAbsolutePath());
protocol.setKeystorePass("changeit");
protocol.setTruststoreFile(truststore.getAbsolutePath());
protocol.setTruststorePass("changeit");
protocol.setKeyAlias("apitester");
return connector;
}
catch (IOException ex) {
throw new IllegalStateException("can't access keystore: [" + "keystore"
+ "] or truststore: [" + "keystore" + "]", ex);
}
}
Spring Boot will automatically configure Tomcat’s RemoteIpValve
if you enable it. This
allows you to transparently use the standard x-forwarded-for
and x-forwarded-proto
headers that most front-end proxy servers add. The valve is switched on by setting one or
both of these properties to something non-empty (these are the conventional values used by
most proxies, and if you only set one the other will be set automatically):
server.tomcat.remote_ip_header=x-forwarded-for server.tomcat.protocol_header=x-forwarded-protocol
If your proxy uses different headers you can customize the valve’s configuration by adding
some entries to application.properties
, e.g.
server.tomcat.remote_ip_header=x-your-remote-ip-header server.tomcat.protocol_header=x-your-protocol-header
The valve is also configured with a default regular expression that matches internal
proxies that are to be trusted. By default, IP addresses in 10/8, 192.168/16, 169.254/16
and 127/8 are trusted. You can customize the valve’s configuration by adding an entry
to application.properties
, e.g.
server.tomcat.internal_proxies=192\.168\.\d{1,3}\.\d{1,3}
Alternatively, you can take complete control of the configuration of the RemoteIpValve
by configuring and adding it in a TomcatEmbeddedServletContainerFactory
bean.
The Spring Boot starters (spring-boot-starter-web
in particular) use Tomcat as an
embedded container by default. You need to exclude those dependencies and include the
Jetty one instead. Spring Boot provides Tomcat and Jetty dependencies bundled together
as separate starters to help make this process as easy as possible.
Example in Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Example in Gradle:
configurations {
compile.exclude module: "spring-boot-starter-tomcat"
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}")
compile("org.springframework.boot:spring-boot-starter-jetty:{spring-boot-version}")
// ...
}
Generally you can follow the advice from
'Discover built-in options for external properties' about
@ConfigurationProperties
(ServerProperties
is the main one here), but also look at
EmbeddedServletContainerCustomizer
. The Jetty APIs are quite rich so once you have
access to the JettyEmbeddedServletContainerFactory
you can modify it in a number
of ways. Or the nuclear option is to add your own JettyEmbeddedServletContainerFactory
.
Tomcat 8 works with Spring Boot, but the default is to use Tomcat 7 (so we can support Java 1.6 out of the box). You should only need to change the classpath to use Tomcat 8 for it to work. For example, using the starter poms in Maven:
<properties>
<tomcat.version>8.0.8</tomcat.version>
</properties>
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
</dependencies>
change the classpath to use Tomcat 8 for it to work.
Jetty 9 works with Spring Boot, but the default is to use Jetty 8 (so we can support Java 1.6 out of the box). You should only need to change the classpath to use Jetty 9 for it to work.
If you are using the starter poms and parent you can just add the Jetty starter and change the version properties, e.g. for a simple webapp or service:
<properties>
<java.version>1.7</java.version>
<jetty.version>9.1.0.v20131115</jetty.version>
<servlet-api.version>3.1.0</servlet-api.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
Any Spring @RestController
in a Spring Boot application should render JSON response by
default as long as Jackson2 is on the classpath. For example:
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
As long as MyThing
can be serialized by Jackson2 (e.g. a normal POJO or Groovy object)
then http://localhost:8080/thing
will serve a JSON representation of it by default.
Sometimes in a browser you might see XML responses because browsers tend to send accept
headers that prefer XML.
If you have the Jackson XML extension (jackson-dataformat-xml
) on the classpath, it will
be used to render XML responses and the very same example as we used for JSON would work.
To use it, add the following dependency to your project:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
You may also want to add a dependency on Woodstox. It’s faster than the default Stax implementation provided by the JDK and also adds pretty print support and improved namespace handling:
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
</dependency>
If Jackson’s XML extension is not available, JAXB (provided by default in the JDK) will
be used, with the additional requirement to have MyThing
annotated as
@XmlRootElement
:
@XmlRootElement
public class MyThing {
private String name;
// .. getters and setters
}
To get the server to render XML instead of JSON you might have to send an
Accept: text/xml
header (or use a browser).
Spring MVC (client and server side) uses HttpMessageConverters
to negotiate content
conversion in an HTTP exchange. If Jackson is on the classpath you already get the
default converter(s) provided by Jackson2ObjectMapperBuilder
.
The ObjectMapper
(or XmlMapper
for Jackson XML converter) instance created by default
have the following customized properties:
-
MapperFeature.DEFAULT_VIEW_INCLUSION
is disabled -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
is disabled
Spring Boot has also some features to make it easier to customize this behavior.
You can configure the ObjectMapper
and XmlMapper
instances using the environment.
Jackson provides an extensive suite of simple on/off features that can be used to
configure various aspects of its processing. These features are described in five enums in
Jackson which map onto properties in the environment:
Jackson enum | Environment property |
---|---|
|
|
|
|
|
|
|
|
|
|
For example, to enable pretty print, set spring.jackson.serialization.indent_output=true
.
Note that, thanks to the use of relaxed binding, the case of indent_output
doesn’t have to match the case of the
corresponding enum constant which is INDENT_OUTPUT
.
If you want to replace the default ObjectMapper
completely, define a @Bean
of that
type and mark it as @Primary
.
Defining a @Bean
of type Jackson2ObjectMapperBuilder
will allow you to customize both
default ObjectMapper
and XmlMapper
(used in MappingJackson2HttpMessageConverter
and
MappingJackson2XmlHttpMessageConverter
respectively).
Another way to customize Jackson is to add beans of type
com.fasterxml.jackson.databind.Module
to your context. They will be registered with every
bean of type ObjectMapper
, providing a global mechanism for contributing custom modules
when you add new features to your application.
Finally, if you provide any @Beans
of type MappingJackson2HttpMessageConverter
then
they will replace the default value in the MVC configuration. Also, a convenience bean is
provided of type HttpMessageConverters
(always available if you use the default MVC
configuration) which has some useful methods to access the default and user-enhanced
message converters.
See also the 'Customize the @ResponseBody rendering' section and the
{sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[WebMvcAutoConfiguration
]
source code for more details.
Spring uses HttpMessageConverters
to render @ResponseBody
(or responses from
@RestController
). You can contribute additional converters by simply adding beans of
that type in a Spring Boot context. If a bean you add is of a type that would have been
included by default anyway (like MappingJackson2HttpMessageConverter
for JSON
conversions) then it will replace the default value. A convenience bean is provided of
type HttpMessageConverters
(always available if you use the default MVC configuration)
which has some useful methods to access the default and user-enhanced message converters
(useful, for example if you want to manually inject them into a custom RestTemplate
).
As in normal MVC usage, any WebMvcConfigurerAdapter
beans that you provide can also
contribute converters by overriding the configureMessageConverters
method, but unlike
with normal MVC, you can supply only additional converters that you need (because Spring
Boot uses the same mechanism to contribute its defaults). Finally, if you opt-out of the
Spring Boot default MVC configuration by providing your own @EnableWebMvc
configuration,
then you can take control completely and do everything manually using
getMessageConverters
from WebMvcConfigurationSupport
.
See the {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[WebMvcAutoConfiguration
]
source code for more details.
Spring Boot embraces the Servlet 3 javax.servlet.http.Part
API to support uploading
files. By default Spring Boot configures Spring MVC with a maximum file of 1Mb per
file and a maximum of 10Mb of file data in a single request. You may override these
values, as well as the location to which intermediate data is stored (e.g., to the /tmp
directory) and the threshold past which data is flushed to disk by using the properties
exposed in the MultipartProperties
class. If you want to specify that files be
unlimited, for example, set the multipart.maxFileSize
property to -1
.
The multipart support is helpful when you want to receive multipart encoded file data as
a @RequestParam
-annotated parameter of type MultipartFile
in a Spring MVC controller
handler method.
See the {sc-spring-boot-autoconfigure}/web/MultipartAutoConfiguration.{sc-ext}[MultipartAutoConfiguration
]
source for more details.
Spring Boot wants to serve all content from the root of your application /
down. If you
would rather map your own servlet to that URL you can do it, but of course you may lose
some of the other Boot MVC features. To add your own servlet and map it to the root
resource just declare a @Bean
of type Servlet
and give it the special bean name
dispatcherServlet
(You can also create a bean of a different type with that name if
you want to switch it off and not replace it).
The easiest way to take complete control over MVC configuration is to provide your own
@Configuration
with the @EnableWebMvc
annotation. This will leave all MVC
configuration in your hands.
A ViewResolver
is a core component of Spring MVC, translating view names in
@Controller
to actual View
implementations. Note that ViewResolvers
are mainly
used in UI applications, rather than REST-style services (a View
is not used to render
a @ResponseBody
). There are many implementations of ViewResolver
to choose from, and
Spring on its own is not opinionated about which ones you should use. Spring Boot, on the
other hand, installs one or two for you depending on what it finds on the classpath and
in the application context. The DispatcherServlet
uses all the resolvers it finds in
the application context, trying each one in turn until it gets a result, so if you are
adding your own you have to be aware of the order and in which position your resolver is
added.
WebMvcAutoConfiguration
adds the following ViewResolvers
to your context:
-
An
InternalResourceViewResolver
with bean id ‘defaultViewResolver’. This one locates physical resources that can be rendered using theDefaultServlet
(e.g. static resources and JSP pages if you are using those). It applies a prefix and a suffix to the view name and then looks for a physical resource with that path in the servlet context (defaults are both empty, but accessible for external configuration viaspring.view.prefix
andspring.view.suffix
). It can be overridden by providing a bean of the same type. -
A
BeanNameViewResolver
with id ‘beanNameViewResolver’. This is a useful member of the view resolver chain and will pick up any beans with the same name as theView
being resolved. It shouldn’t be necessary to override or replace it. -
A
ContentNegotiatingViewResolver
with id ‘viewResolver’ is only added if there are actually beans of typeView
present. This is a ‘master’ resolver, delegating to all the others and attempting to find a match to the ‘Accept’ HTTP header sent by the client. There is a useful blog aboutContentNegotiatingViewResolver
that you might like to study to learn more, and also look at the source code for detail. You can switch off the auto-configuredContentNegotiatingViewResolver
by defining a bean named ‘viewResolver’. -
If you use Thymeleaf you will also have a
ThymeleafViewResolver
with id ‘thymeleafViewResolver’. It looks for resources by surrounding the view name with a prefix and suffix (externalized tospring.thymeleaf.prefix
andspring.thymeleaf.suffix
, defaults ‘classpath:/templates/’ and ‘.html’ respectively). It can be overridden by providing a bean of the same name. -
If you use FreeMarker you will also have a
FreeMarkerViewResolver
with id ‘freeMarkerViewResolver’. It looks for resources in a loader path (externalized tospring.freemarker.templateLoaderPath
, default ‘classpath:/templates/’) by surrounding the view name with a prefix and suffix (externalized tospring.freemarker.prefix
andspring.freemarker.suffix
, with empty and ‘.ftl’ defaults respectively). It can be overridden by providing a bean of the same name. -
If you use Groovy templates (actually if groovy-templates is on your classpath) you will also have a
Groovy TemplateViewResolver
with id ‘groovyTemplateViewResolver’. It looks for resources in a loader path by surrounding the view name with a prefix and suffix (externalized tospring.groovy.template.prefix
andspring.groovy.template.suffix
, defaults ‘classpath:/templates/’ and ‘.tpl’ respectively). It can be overriden by providing a bean of the same name. -
If you use Velocity you will also have a
VelocityViewResolver
with id ‘velocityViewResolver’. It looks for resources in a loader path (externalized tospring.velocity.resourceLoaderPath
, default ‘classpath:/templates/’) by surrounding the view name with a prefix and suffix (externalized tospring.velocity.prefix
andspring.velocity.suffix
, with empty and ‘.vm’ defaults respectively). It can be overridden by providing a bean of the same name.
Check out {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[WebMvcAutoConfiguration
],
{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration
],
{sc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{sc-ext}[FreeMarkerAutoConfiguration
],
{sc-spring-boot-autoconfigure}/groovy/template/GroovyTemplateAutoConfiguration.{sc-ext}[GroovyTemplateAutoConfiguration
] and
{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[VelocityAutoConfiguration
]
Spring Boot has no mandatory logging dependence, except for the commons-logging
API, of
which there are many implementations to choose from. To use Logback
you need to include it, and some bindings for commons-logging
on the classpath. The
simplest way to do that is through the starter poms which all depend on
spring-boot-starter-logging
. For a web application you only need
spring-boot-starter-web
since it depends transitively on the logging starter.
For example, using Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Spring Boot has a LoggingSystem
abstraction that attempts to configure logging based on
the content of the classpath. If Logback is available it is the first choice.
If the only change you need to make to logging is to set the levels of various loggers
then you can do that in application.properties
using the "logging.level" prefix, e.g.
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
You can also set the location of a file to log to (in addition to the console) using "logging.file".
To configure the more fine-grained settings of a logging system you need to use the native
configuration format supported by the LoggingSystem
in question. By default Spring Boot
picks up the native configuration from its default location for the system (e.g.
classpath:logback.xml
for Logback), but you can set the location of the config file
using the "logging.config" property.
If you put a logback.xml
in the root of your classpath it will be picked up from there.
Spring Boot provides a default base configuration that you can include if you just want
to set levels, e.g.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
If you look at the default logback.xml
in the spring-boot jar you will see that it uses
some useful System properties which the LoggingSystem
takes care of creating for you.
These are:
-
${PID}
the current process ID. -
${LOG_FILE}
iflogging.file
was set in Boot’s external configuration. -
${LOG_PATH}
iflogging.path
was set (representing a directory for log files to live in).
Spring Boot also provides some nice ANSI colour terminal output on a console (but not in
a log file) using a custom Logback converter. See the default base.xml
configuration
for details.
If Groovy is on the classpath you should be able to configure Logback with
logback.groovy
as well (it will be given preference if present).
Spring Boot also supports either Log4j or
Log4j 2 for logging configuration, but only if one
of them is on the classpath. If you are using the starter poms for assembling
dependencies that means you have to exclude Logback and then include your chosen version
of Log4j instead. If you aren’t using the starter poms then you need to provide
commons-logging
(at least) in addition to your chosen version of Log4j.
The simplest path is probably through the starter poms, even though it requires some jiggling with excludes, .e.g. in Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
To use Log4j 2, simply depend on spring-boot-starter-log4j2
rather than
spring-boot-starter-log4j
.
Note
|
The use of one of the Log4j starters gathers together the dependencies for
common logging requirements (e.g. including having Tomcat use java.util.logging but
configuring the output using Log4j or Log4j 2). See the Actuator Log4j or Log4j 2
samples for more detail and to see it in action.
|
To override the default settings just define a @Bean
of your own of type DataSource
.
Spring Boot provides a utility builder class DataSourceBuilder
that can be used
to create one of the standard ones (if it is on the classpath), or you can just create
your own, and bind it to a set of Environment
properties e.g.
@Bean
@ConfigurationProperties(prefix="datasource.mine")
public DataSource dataSource() {
return new FancyDataSource();
}
datasource.mine.jdbcUrl=jdbc:h2:mem:mydb
datasource.mine.user=sa
datasource.mine.poolSize=30
See 'spring-boot-features.adoc' in the
‘Spring Boot features’ section and the
{sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[DataSourceAutoConfiguration
]
class for more details.
Creating more than one data source works the same as creating the first one. You might
want to mark one of them as @Primary
if you are using the default auto-configuration for
JDBC or JPA (then that one will be picked up by any @Autowired
injections).
@Bean
@Primary
@ConfigurationProperties(prefix="datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
Spring Data can create implementations for you of @Repository
interfaces of various
flavours. Spring Boot will handle all of that for you as long as those @Repositories
are included in the same package (or a sub-package) of your @EnableAutoConfiguration
class.
For many applications all you will need is to put the right Spring Data dependencies on
your classpath (there is a spring-boot-starter-data-jpa
for JPA and a
spring-boot-starter-data-mongodb
for Mongodb), create some repository interfaces to handle your
@Entity
objects. Examples are in the {github-code}/spring-boot-samples/spring-boot-sample-data-jpa[JPA sample]
or the {github-code}/spring-boot-samples/spring-boot-sample-data-mongodb[Mongodb sample].
Spring Boot tries to guess the location of your @Repository
definitions, based on the
@EnableAutoConfiguration
it finds. To get more control, use the @EnableJpaRepositories
annotation (from Spring Data JPA).
Spring Boot tries to guess the location of your @Entity
definitions, based on the
@EnableAutoConfiguration
it finds. To get more control, you can use the @EntityScan
annotation, e.g.
@Configuration
@EnableAutoConfiguration
@EntityScan(basePackageClasses=City.class)
public class Application {
//...
}
Spring Data JPA already provides some vendor-independent configuration options (e.g. for SQL logging) and Spring Boot exposes those, and a few more for hibernate as external configuration properties. The most common options to set are:
spring.jpa.hibernate.ddl-auto: create-drop spring.jpa.hibernate.naming_strategy: org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.database: H2 spring.jpa.show-sql: true
(Because of relaxed data binding hyphens or underscores should work equally well as
property keys.) The ddl-auto
setting is a special case in that it has different
defaults depending on whether you are using an embedded database (create-drop
) or not
(none
). In addition all properties in spring.jpa.properties.*
are passed through as
normal JPA properties (with the prefix stripped) when the local EntityManagerFactory
is
created.
See {sc-spring-boot-autoconfigure}/orm/jpa/HibernateJpaAutoConfiguration.{sc-ext}[HibernateJpaAutoConfiguration
]
and {sc-spring-boot-autoconfigure}/orm/jpa/JpaBaseConfiguration.{sc-ext}[JpaBaseConfiguration
]
for more details.
To take full control of the configuration of the EntityManagerFactory
, you need to add
a @Bean
named ‘entityManagerFactory’. Spring Boot auto-configuration switches off its
entity manager based on the presence of a bean of that type.
Even if the default EntityManagerFactory
works fine, you will need to define a new one
because otherwise the presence of the second bean of that type will switch off the
default. To make it easy to do that you can use the convenient EntityManagerBuilder
provided by Spring Boot, or if you prefer you can just use the
LocalContainerEntityManagerFactoryBean
directly from Spring ORM.
Example:
// add two data sources configured as above
@Bean
public LocalContainerEntityManagerFactoryBean customerEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(customerDataSource())
.packages(Customer.class)
.persistenceUnit("customers")
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
return builder
.dataSource(orderDataSource())
.packages(Order.class)
.persistenceUnit("orders")
.build();
}
The configuration above almost works on its own. To complete the picture you need to
configure TransactionManagers
for the two EntityManagers
as well. One of them could
be picked up by the default JpaTransactionManager
in Spring Boot if you mark it as
@Primary
. The other would have to be explicitly injected into a new instance. Or you
might be able to use a JTA transaction manager spanning both.
Spring doesn’t require the use of XML to configure the JPA provider, and Spring Boot
assumes you want to take advantage of that feature. If you prefer to use persistence.xml
then you need to define your own @Bean
of type LocalEntityManagerFactoryBean
(with
id ‘entityManagerFactory’, and set the persistence unit name there.
See
JpaBaseConfiguration
for the default settings.
Spring Data JPA and Spring Data Mongo can both create Repository
implementations for you
automatically. If they are both present on the classpath, you might have to do some extra
configuration to tell Spring Boot which one (or both) you want to create repositories for
you. The most explicit way to do that is to use the standard Spring Data
@Enable*Repositories
and tell it the location of your Repository
interfaces
(where ‘*’ is ‘Jpa’ or ‘Mongo’ or both).
There are also flags spring.data.*.repositories.enabled
that you can use to switch the
auto-configured repositories on and off in external configuration. This is useful for
instance in case you want to switch off the Mongo repositories and still use the
auto-configured MongoTemplate
.
The same obstacle and the same features exist for other auto-configured Spring Data repository types (Elasticsearch, Solr). Just change the names of the annotations and flags respectively.
An SQL database can be initialized in different ways depending on what your stack is. Or of course you can do it manually as long as the database is a separate process.
JPA has features for DDL generation, and these can be set up to run on startup against the database. This is controlled through two external properties:
-
spring.jpa.generate-ddl
(boolean) switches the feature on and off and is vendor independent. -
spring.jpa.hibernate.ddl-auto
(enum) is a Hibernate feature that controls the behavior in a more fine-grained way. See below for more detail.
You can set spring.jpa.hibernate.ddl-auto
explicitly and the standard Hibernate property
values are none
, validate
, update
, create-drop
. Spring Boot chooses a default
value for you based on whether it thinks your database is embedded (default create-drop
)
or not (default none
). An embedded database is detected by looking at the Connection
type: hsqldb
, h2
and derby
are embedded, the rest are not. Be careful when switching
from in-memory to a ‘real’ database that you don’t make assumptions about the existence of
the tables and data in the new platform. You either have to set ddl-auto
explicitly, or
use one of the other mechanisms to initialize the database.
In addition, a file named import.sql
in the root of the classpath will be executed on
startup. This can be useful for demos and for testing if you are careful, but probably
not something you want to be on the classpath in production. It is a Hibernate feature
(nothing to do with Spring).
Spring JDBC has a DataSource
initializer feature. Spring Boot enables it by default and
loads SQL from the standard locations schema.sql
and data.sql
(in the root of the
classpath). In addition Spring Boot will load the schema-${platform}.sql
and data-${platform}.sql
files (if present), where
platform
is the value of spring.datasource.platform
, e.g. you might choose to set
it to the vendor name of the database (hsqldb
, h2
, oracle
, mysql
,
postgresql
etc.). Spring Boot enables the failfast feature of the Spring JDBC
initializer by default, so if the scripts cause exceptions the application will fail
to start. The script locations can be changed by setting spring.datasource.schema
and
spring.datasource.data
, and neither location will be processed if
spring.datasource.initialize=false
.
To disable the failfast you can set spring.datasource.continueOnError=true
. This can be
useful once an application has matured and been deployed a few times, since the scripts
can act as ‘poor man’s migrations’ — inserts that fail mean that the data is already
there, so there would be no need to prevent the application from running, for instance.
If you want to use the schema.sql
initialization in a JPA app (with
Hibernate) then ddl-auto=create-drop
will lead to errors if
Hibernate tries to create the same tables. To avoid those errors set
ddl-auto
explicitly to "" (preferable) or "none". Whether or not you use
ddl-auto=create-drop
you can always use data.sql
to initialize new
data.
If you are using Spring Batch then it comes pre-packaged with SQL initialization scripts
for most popular database platforms. Spring Boot will detect your database type, and
execute those scripts by default, and in this case will switch the fail fast setting to
false (errors are logged but do not prevent the application from starting). This is
because the scripts are known to be reliable and generally do not contain bugs, so errors
are ignorable, and ignoring them makes the scripts idempotent. You can switch off the
initialization explicitly using spring.batch.initializer.enabled=false
.
Spring Boot works fine with higher level migration tools Flyway (SQL-based) and Liquibase (XML). In general we prefer Flyway because it is easier on the eyes, and it isn’t very common to need platform independence: usually only one or at most couple of platforms is needed.
To automatically run Flyway database migrations on startup, add the
org.flywaydb:flyway-core
to your classpath.
The migrations are scripts in the form V<VERSION>__<NAME>.sql
(with <VERSION>
an
underscore-separated version, e.g. ‘1’ or ‘2_1’). By default they live in a folder
classpath:db/migration
but you can modify that using flyway.locations
(a list). See
the Flyway class from flyway-core for details of available settings like schemas etc. In
addition Spring Boot provides a small set of properties in
{sc-spring-boot-autoconfigure}/flyway/FlywayProperties.{sc-ext}[FlywayProperties
]
that can be used to disable the migrations, or switch off the location checking.
By default Flyway will autowire the (@Primary
) DataSource
in your context and
use that for migrations. If you like to use a different DataSource
you can create
one and mark its @Bean
as @FlywayDataSource
- if you do that remember to create
another one and mark it as @Primary
if you want two data sources.
Or you can use Flyway’s native DataSource
by setting flyway.[url,user,password]
in external properties.
There is a {github-code}/spring-boot-samples/spring-boot-sample-flyway[Flyway sample] so you can see how to set things up.
To automatically run Liquibase database migrations on startup, add the
org.liquibase:liquibase-core
to your classpath.
The master change log is by default read from db/changelog/db.changelog-master.yaml
but
can be set using liquibase.change-log
. See
{sc-spring-boot-autoconfigure}/liquibase/LiquibaseProperties.{sc-ext}[LiquibaseProperties
]
for details of available settings like contexts, default schema etc.
There is a {github-code}/spring-boot-samples/spring-boot-sample-liquibase[Liquibase sample] so you can see how to set things up.
Spring Batch auto configuration is enabled by adding @EnableBatchProcessing
(from Spring Batch) somewhere in your context.
By default it executes all Jobs
in the application context on startup (see
{sc-spring-boot-autoconfigure}/batch/JobLauncherCommandLineRunner.{sc-ext}[JobLauncherCommandLineRunner]
for details). You can narrow down to a specific job or jobs by specifying
spring.batch.job.names
(comma-separated job name patterns).
If the application context includes a JobRegistry
then the jobs in
spring.batch.job.names
are looked up in the registry instead of being autowired from the
context. This is a common pattern with more complex systems where multiple jobs are
defined in child contexts and registered centrally.
See {sc-spring-boot-autoconfigure}/batch/BatchAutoConfiguration.{sc-ext}[BatchAutoConfiguration] and @EnableBatchProcessing for more details.
In a standalone application the Actuator HTTP port defaults to the same as the main HTTP
port. To make the application listen on a different port set the external property
management.port
. To listen on a completely different network address (e.g. if you have
an internal network for management and an external one for user applications) you can
also set management.address
to a valid IP address that the server is able to bind to.
For more detail look at the
{sc-spring-boot-actuator}/autoconfigure/ManagementServerProperties.{sc-ext}[ManagementServerProperties
]
source code and
'production-ready-features.adoc'
in the ‘Production-ready features’ section.
Spring Boot installs a ‘whitelabel’ error page that you will see in browser client if
you encounter a server error (machine clients consuming JSON and other media types should
see a sensible response with the right error code). To switch it off you can set
error.whitelabel.enabled=false
, but normally in addition or alternatively to that you
will want to add your own error page replacing the whitelabel one. Exactly how you do this
depends on the templating technology that you are using. For example, if you are using
Thymeleaf you would add an error.html
template and if you are using FreeMarker you would
add an error.ftl
template. In general what you need is a View
that resolves with a name
of error
, and/or a @Controller
that handles the /error
path. Unless you replaced some
of the default configuration you should find a BeanNameViewResolver
in your
ApplicationContext
so a @Bean
with id error
would be a simple way of doing that.
Look at {sc-spring-boot-autoconfigure}/web/ErrorMvcAutoConfiguration.{sc-ext}[ErrorMvcAutoConfiguration
] for more options.
See also the section on Error Handling for details of how to register handlers in the servlet container.
If you define a @Configuration
with @EnableWebSecurity
anywhere in your application
it will switch off the default webapp security settings in Spring Boot. To tweak the
defaults try setting properties in security.*
(see
{sc-spring-boot-autoconfigure}/security/SecurityProperties.{sc-ext}[SecurityProperties
]
for details of available settings) and SECURITY
section of
Common application properties.
If you provide a @Bean
of type AuthenticationManager
the default one will not be
created, so you have the full feature set of Spring Security available (e.g.
various authentication options).
Spring Security also provides a convenient AuthenticationManagerBuilder
which can be
used to build an AuthenticationManager
with common options. The recommended way to
use this in a webapp is to inject it into a void method in a
WebSecurityConfigurerAdapter
, e.g.
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("barry").password("password").roles("USER"); // ... etc.
}
// ... other stuff for application security
}
You will get the best results if you put this in a nested class, or a standalone class
(i.e. not mixed in with a lot of other @Beans
that might be allowed to influence the
order of instantiation). The {github-code}/spring-boot-samples/spring-boot-sample-web-secure[secure web sample]
is a useful template to follow.
If you experience instantiation issues (e.g. using JDBC or JPA for the user detail store)
it might be worth extracting the AuthenticationManagerBuilder
callback into a
GlobalAuthenticationConfigurerAdapter
(in the init()
method so it happens before the
authentication manager is needed elsewhere), e.g.
@Configuration
public class AuthenticationManagerConfiguration extends
GlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) {
auth.inMemoryAuthentication() // ... etc.
}
}
Ensuring that all your main endpoints are only available over HTTPS is an important
chore for any application. If you are using Tomcat as a servlet container, then
Spring Boot will add Tomcat’s own RemoteIpValve
automatically if it detects some
environment settings, and you should be able to rely on the HttpServletRequest
to
report whether it is secure or not (even downstream of a proxy server that handles the
real SSL termination). The standard behavior is determined by the presence or absence of
certain request headers (x-forwarded-for
and x-forwarded-proto
), whose names are
conventional, so it should work with most front end proxies. You can switch on the valve
by adding some entries to application.properties
, e.g.
server.tomcat.remote_ip_header=x-forwarded-for
server.tomcat.protocol_header=x-forwarded-proto
(The presence of either of those properties will switch on the valve. Or you can add the
RemoteIpValve
yourself by adding a TomcatEmbeddedServletContainerFactory
bean.)
Spring Security can also be configured to require a secure channel for all (or some
requests). To switch that on in a Spring Boot application you just need to set
security.require_https
to true
in application.properties
.
There are several options for hot reloading. Running in an IDE (especially with debugging on) is a good way to do development (all modern IDEs allow reloading of static resources and usually also hot-swapping of Java class changes). The Maven and Gradle plugins also support running from the command line with reloading of static files. You can use that with an external css/js compiler process if you are writing that code with higher level tools.
If you are using Thymeleaf, then set spring.thymeleaf.cache
to false
. See
{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[ThymeleafAutoConfiguration
]
for other Thymeleaf customization options.
If you are using FreeMarker, then set spring.freemarker.cache
to false
. See
{sc-spring-boot-autoconfigure}/freemarker/FreeMarkerAutoConfiguration.{sc-ext}[FreeMarkerAutoConfiguration
]
for other FreeMarker customization options.
If you are using Groovy templates, then set spring.groovy.template.cache
to false
. See
{sc-spring-boot-autoconfigure}/groovy/template/GroovyTemplateAutoConfiguration.{sc-ext}[GroovyTemplateAutoConfiguration
]
for other Groovy customization options.
If you are using Velocity, then set spring.velocity.cache
to false
. See
{sc-spring-boot-autoconfigure}/velocity/VelocityAutoConfiguration.{sc-ext}[VelocityAutoConfiguration
]
for other Velocity customization options.
Modern IDEs (Eclipse, IDEA, etc.) all support hot swapping of bytecode, so if you make a change that doesn’t affect class or method signatures it should reload cleanly with no side effects.
Spring Loaded goes a little further in
that it can reload class definitions with changes in the method signatures. With some
customization it can force an ApplicationContext
to refresh itself (but there is no
general mechanism to ensure that would be safe for a running application anyway, so it
would only ever be a development time trick probably).
You need to jump through a few hoops if you want to use Spring Loaded in combination with Gradle and IntelliJ. By default, IntelliJ will compile classes into a different location than Gradle, causing Spring Loaded monitoring to fail.
To configure IntelliJ correctly you can use the idea
Gradle plugin:
buildscript {
repositories { jcenter() }
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}"
classpath 'org.springframework:springloaded:1.2.0.RELEASE'
}
}
apply plugin: 'idea'
idea {
module {
inheritOutputDirs = false
outputDir = file("$buildDir/classes/main/")
}
}
// ...
Note
|
IntelliJ must be configured to use the same Java version as the command line Gradle
task and springloaded must be included as a buildscript dependency.
|
You can also additionally enable ‘Make Project Automatically’ inside Intellij to automatically compile your code whenever a file is saved.
If you use a Maven build that inherits directly or indirectly from spring-boot-dependencies
(for instance spring-boot-starter-parent
) but you want to override a specific
third-party dependency you can add appropriate <properties>
elements. Browse
the {github-code}/spring-boot-dependencies/pom.xml[spring-boot-dependencies
]
POM for a complete list of properties. For example, to pick a different slf4j
version
you would add the following:
<properties>
<slf4j.version>1.7.5<slf4j.version>
</properties>
Note
|
This only works if your Maven project inherits (directly or indirectly) from
spring-boot-dependencies . If you have added spring-boot-dependencies in your
own dependencyManagement section with <scope>import</scope> you have to redefine
the artifact yourself instead of overriding the property .
|
Warning
|
Each Spring Boot release is designed and tested against a specific set of third-party dependencies. Overriding versions may cause compatibility issues. |
The spring-boot-maven-plugin
can be used to create an executable ‘fat’ JAR. If you
are using the spring-boot-starter-parent
POM you can simply declare the plugin and
your jars will be repackaged:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
If you are not using the parent POM you can still use the plugin, however, you must
additionally add an <executions>
section:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{spring-boot-version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See the {spring-boot-maven-plugin-site}/usage.html[plugin documentation] for full usage details.
If you want to use your project as a library jar for other projects to depend on, and in addition have an executable (e.g. demo) version of it, you will want to configure the build in a slightly different way.
For Maven the normal JAR plugin and the Spring Boot plugin both have a ‘classifier’ configuration that you can add to create an additional JAR. Example (using the Spring Boot Starter Parent to manage the plugin versions and other configuration defaults):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
Two jars are produced, the default one, and an executable one using the Boot plugin with classifier ‘exec’.
For Gradle users the steps are similar. Example:
bootRepackage {
classifier = 'exec'
}
Most nested libraries in an executable jar do not need to be unpacked in order to run,
however, certain libraries can have problems. For example, JRuby includes its own nested
jar support which assumes that the jruby-complete.jar
is always directly available as a
file in its own right.
To deal with any problematic libraries, you can flag that specific nested jars should be automatically unpacked to the ‘temp folder’ when the executable jar first runs.
For example, to indicate that JRuby should be flagged for unpack using the Maven Plugin you would add the following configuration:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<requiresUnpack>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
</dependency>
</requiresUnpack>
</configuration>
</plugin>
</plugins>
</build>
And to do that same with Gradle:
springBoot {
requiresUnpack = ['org.jruby:jruby-complete']
}
Often if you have an executable and a non-executable jar as build products, the executable
version will have additional configuration files that are not needed in a library jar.
E.g. the application.yml
configuration file might excluded from the non-executable JAR.
Here’s how to do that in Maven:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>exec</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<!-- Need this to ensure application.yml is excluded -->
<forceCreation>true</forceCreation>
<excludes>
<exclude>application.yml</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
In Gradle you can create a new JAR archive with standard task DSL features, and then have
the bootRepackage
task depend on that one using its withJarTask
property:
jar {
baseName = 'spring-boot-sample-profile'
version = '0.0.0'
excludes = ['**/application.yml']
}
task('execJar', type:Jar, dependsOn: 'jar') {
baseName = 'spring-boot-sample-profile'
version = '0.0.0'
classifier = 'exec'
from sourceSets.main.output
}
bootRepackage {
withJarTask = tasks['execJar']
}
To attach a remote debugger to a Spring Boot application started with Maven you can use
the jvmArguments
property of the {spring-boot-maven-plugin-site}/[maven plugin].
Check {spring-boot-maven-plugin-site}/examples/run-debug.html[this example] for more details.
To attach a remote debugger to a Spring Boot application started with Gradle you can use
the applicationDefaultJvmArgs
in build.gradle
or --debug-jvm
command line option.
build.gradle
:
applicationDefaultJvmArgs = [
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
]
Command line:
$ gradle run --debug-jvm
Check {gradle-userguide}/application_plugin.html[Gradle Application Plugin] for more details.
To build with Ant you need to grab dependencies, compile and then create a jar or war archive as normal. To make it executable:
-
Use the appropriate launcher as a
Main-Class
, e.g.JarLauncher
for a jar file, and specify the other properties it needs as manifest entries, principally aStart-Class
. -
Add the runtime dependencies in a nested ‘lib’ directory (for a jar) and the
provided
(embedded container) dependencies in a nestedlib-provided
directory. Remember not to compress the entries in the archive. -
Add the
spring-boot-loader
classes at the root of the archive (so theMain-Class
is available).
Example:
<target name="build" depends="compile">
<copy todir="target/classes/lib">
<fileset dir="lib/runtime" />
</copy>
<jar destfile="target/spring-boot-sample-actuator-${spring-boot.version}.jar" compress="false">
<fileset dir="target/classes" />
<fileset dir="src/main/resources" />
<zipfileset src="lib/loader/spring-boot-loader-jar-${spring-boot.version}.jar" />
<manifest>
<attribute name="Main-Class" value="org.springframework.boot.loader.JarLauncher" />
<attribute name="Start-Class" value="${start-class}" />
</manifest>
</jar>
</target>
The Actuator Sample has a build.xml
that should work if you run it with
$ ant -lib <path_to>/ivy-2.2.jar
after which you can run the application with
$ java -jar target/*.jar
Use the SpringBootServletInitializer
base class, which is picked up by Spring’s
Servlet 3.0 support on deployment. Add an extension of that to your project and build a
war file as normal. For more detail, see the
‘Converting a jar Project to a war’ guide
on the spring.io website and the sample below.
The war file can also be executable if you use the Spring Boot build tools. In that case
the embedded container classes (to launch Tomcat for instance) have to be added to the
war in a lib-provided
directory. The tools will take care of that as long as the
dependencies are marked as ‘provided’ in Maven or Gradle. Here’s a Maven example
{github-code}/spring-boot-samples/spring-boot-sample-traditional/pom.xml[in the Boot Samples].
Older Servlet containers don’t have support for the ServletContextInitializer
bootstrap
process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers
but you are going to need to add a web.xml
to your application and configure it to load
an ApplicationContext
via a DispatcherServlet
.
For a non-web application it should be easy (throw away the code that creates your
ApplicationContext
and replace it with calls to SpringApplication
or
SpringApplicationBuilder
). Spring MVC web applications are generally amenable to first
creating a deployable war application, and then migrating it later to an executable war
and/or jar. Useful reading is in the Getting
Started Guide on Converting a jar to a war.
Create a deployable war by extending SpringBootServletInitializer
(e.g. in a class
called Application
), and add the Spring Boot @EnableAutoConfiguration
annotation.
Example:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
Remember that whatever you put in the sources
is just a Spring ApplicationContext
and
normally anything that already works should work here. There might be some beans you can
remove later and let Spring Boot provide its own defaults for them, but it should be
possible to get something working first.
Static resources can be moved to /public
(or /static
or /resources
or
/META-INF/resources
) in the classpath root. Same for messages.properties
(Spring Boot
detects this automatically in the root of the classpath).
Vanilla usage of Spring DispatcherServlet
and Spring Security should require no further
changes. If you have other features in your application, using other servlets or filters
for instance, then you may need to add some configuration to your Application
context,
replacing those elements from the web.xml
as follows:
-
A
@Bean
of typeServlet
orServletRegistrationBean
installs that bean in the container as if it was a<servlet/>
and<servlet-mapping/>
inweb.xml
. -
A
@Bean
of typeFilter
orFilterRegistrationBean
behaves similarly (like a<filter/>
and<filter-mapping/>
. -
An
ApplicationContext
in an XML file can be added to an@Import
in yourApplication
. Or simple cases where annotation configuration is heavily used already can be recreated in a few lines as@Bean
definitions.
Once the war is working we make it executable by adding a main
method to our
Application
, e.g.
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
Applications can fall into more than one category:
-
Servlet 3.0 applications with no
web.xml
. -
Applications with a
web.xml
. -
Applications with a context hierarchy.
-
Applications without a context hierarchy.
All of these should be amenable to translation, but each might require slightly different tricks.
Servlet 3.0 applications might translate pretty easily if they already use the Spring
Servlet 3.0 initializer support classes. Normally all the code from an existing
WebApplicationInitializer
can be moved into a SpringBootServletInitializer
. If your
existing application has more than one ApplicationContext
(e.g. if it uses
AbstractDispatcherServletInitializer
) then you might be able to squash all your context
sources into a single SpringApplication
. The main complication you might encounter is if
that doesn’t work and you need to maintain the context hierarchy. See the
entry on building a hierarchy for
examples. An existing parent context that contains web-specific features will usually
need to be broken up so that all the ServletContextAware
components are in the child
context.
Applications that are not already Spring applications might be convertible to a Spring Boot application, and the guidance above might help, but your mileage may vary.