spring-boot/spring-boot-docs/src/main/asciidoc/howto.adoc

1435 lines
59 KiB
Plaintext
Raw Normal View History

[[howto]]
= ``How-to'' guides
[partintro]
--
This section provides answers to some common '``how do I do that...''' type of questions
that often arise when using Spring Boot. This is by no means an exhaustive list, but it
does cover quite a lot.
If you are having a specific problem that we don't cover here, you might want to check out
http://stackoverflow.com/tags/spring-boot[stackoverflow.com] to see if someone has
already provided an answer; this is also a great place to ask new questions (please use
the `spring-boot` tag).
We're also more than happy to extend this section; If you want to add a ``how-to'' you
can send us a {github-code}[pull request].
--
[[howto-spring-boot-application]]
== Spring Boot application
[[howto-troubleshoot-auto-configuration]]
=== Troubleshoot auto-configuration
2014-04-16 17:48:36 +08:00
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 the `autoconfig` endpoint (`/autoconfig' or the JMX equivalent) for
the same information.
* Look for classes that are `@ConfigurationProperties` (e.g.
2014-04-16 17:48:36 +08:00
{sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[`ServerProperties`])
and read from there the available external configuration options. The
`@ConfigurationProperties` has a `name` attribute which acts as a prefix to external
properties, thus `ServerProperties` has `prefix="server"` and its configuration properties
are `server.port`, `server.address` etc. In a running Actuator app look at the
`configprops` endpoint.
* Look for use of `RelaxedEnvironment` to pull configuration values explicitly out of the
`Environment`. It often is used with a prefix.
* Look for `@Value` annotations that bind directly to the `Environment`. This is less
flexible than the `RelaxedEnvironment` approach, but does allow some relaxed binding,
specifically for OS environment variables (so `CAPITALS_AND_UNDERSCORES` are synonyms
for `period.separated`).
* Look for `@ConditionalOnExpression` annotations that switch features on and off in
response to SpEL expressions, normally evaluated with place-holders resolved from the
`Environment`.
[[howto-customize-the-environment-or-application-context]]
=== Customize the Environment or ApplicationContext before it starts
A `SpringApplication` has `ApplicationListeners` and `ApplicationContextInitializers` that
are used to apply customizations to the context or environment. Spring Boot loads a number
of such customizations for use internally from `META-INF/spring.factories`. There is more
than one way to register additional ones:
* Programmatically per application by calling the `addListeners` and `addInitializers`
methods on `SpringApplication` before you run it.
* Declaratively per application by setting `context.initializer.classes` or
`context.listener.classes`.
* Declaratively for all applications by adding a `META-INF/spring.factories` and packaging
a jar file that the applications all use as a library.
The `SpringApplication` sends some special `ApplicationEvents` to the listeners (even
some before the context is created), and then registers the listeners for events published
by the `ApplicationContext` as well. See
'<<spring-boot-features.adoc#boot-features-application-events-and-listeners>>' in the
``Spring Boot features'' section for a complete list.
[[howto-build-an-application-context-hierarchy]]
=== Build an ApplicationContext hierarchy (adding a parent or root context)
You can use the `ApplicationBuilder` class to create parent/child `ApplicationContext`
hierarchies. See '<<spring-boot-features.adoc#boot-features-fluent-builder-api>>'
in the ``Spring Boot features'' section for more information.
[[howto-create-a-non-web-application]]
=== Create a non-web application
Not all Spring applications have to be web applications (or web services). If you want to
execute some code in a `main` method, but also bootstrap a Spring application to set up
the infrastructure to use, then it's easy with the `SpringApplication` features of Spring
Boot. A `SpringApplication` changes its `ApplicationContext` class depending on whether it
thinks it needs a web application or not. The first thing you can do to help it is to just
leave the 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.
[[howto-properties-and-configuration]]
== Properties & configuration
[[howto-externalize-configuration]]
=== Externalize the configuration of SpringApplication
A `SpringApplication` has bean properties (mainly setters) so you can use its Java API as
you create the application to modify its behavior. Or you can externalize the
configuration using properties in `spring.main.*`. E.g. in `application.properties` you
might have.
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
----
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.
2014-03-19 02:26:15 +08:00
NOTE: The example above also demonstrates how flexible binding allows the use of
underscores (`_`) as well as dashes (`-`) in property names.
[[howto-change-the-location-of-external-properties]]
=== Change the location of external properties of an application
By default properties from different sources are added to the Spring `Environment` in a
defined order (see '<<spring-boot-features.adoc#boot-features-external-config>>' 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 to `application` 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 separate `Environment` 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.
[[howto-use-short-command-line-arguments]]
=== Use ``short'' command line arguments
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.
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
----
server.port=${port:8080}
----
TIP: If you have enabled maven filtering for the `application.properties` you may want
to avoid using `${*}` for the tokens to filter as 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
http://maven.apache.org/plugins/maven-resources-plugin/resources-mojo.html#delimiters[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.
[[howto-use-yaml-for-external-properties]]
=== Use YAML for external properties
YAML is a superset of JSON and as such is a very convenient syntax for storing external
properties in a hierarchical format. E.g.
[source,yaml,indent=0,subs="verbatim,quotes,attributes"]
----
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
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
----
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#boot-features-external-config-yaml>>' in
the ``Spring Boot features'' section for more information
about YAML.
[[howto-set-active-spring-profiles]]
=== Set the active Spring profiles
The Spring `Environment` has an API for this, but normally you would set a System profile
(`spring.profiles.active`) or an OS environment variable (`SPRING_PROFILES_ACTIVE`). E.g.
launch your application with a `-D` argument (remember to put it before the main class
or jar archive):
[indent=0,subs="verbatim,quotes,attributes"]
----
$ 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.
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
----
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#boot-features-profiles>>' in
the ``Spring Boot features'' section for more information.
[[howto-change-configuration-depending-on-the-environment]]
=== Change configuration depending on the environment
A YAML file is actually a sequence of documents separated by `---` lines, and each
document is parsed separately to a flattened map.
If a YAML document contains a `spring.profiles` key, then the profiles value
(comma-separated list of profiles) is fed into the Spring
`Environment.acceptsProfiles()` and if any of those profiles is active that document is
included in the final merge (otherwise not).
Example:
[source,yaml,indent=0,subs="verbatim,quotes,attributes"]
----
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.
[[howto-discover-build-in-options-for-external-properties]]
=== Discover built-in options for external properties
Spring Boot binds external properties from `application.properties` (or `.yml`) (and
other places) into an application at runtime. There is not (and technically cannot be)
an exhaustive list of all supported properties in a single location because contributions
can come from additional jar files on your classpath.
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 <<appendix-application-properties#common-application-properties,
`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`.
[[howto-embedded-servlet-containers]]
== Embedded servlet containers
[[howto-add-a-servlet-filter-or-servletcontextlistener]]
=== Add a Servlet, Filter or ServletContextListener to an application
`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.
[[howto-change-the-http-port]]
=== Change the HTTP port
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#boot-features-customizing-embedded-containers>>'
in the ``Spring Boot features'' section, or the
{sc-spring-boot-autoconfigure}/web/ServerProperties.{sc-ext}[`ServerProperties`] source
code.
[[howto-user-a-random-unassigned-http-port]]
=== Use a random unassigned HTTP port
To scan for a free port (using OS natives to prevent clashes) use `server.port=0`.
[[howto-discover-the-http-port-at-runtime]]
=== Discover the HTTP port at runtime
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 really useful thing to do in is to use `@IntegrationTest` to set `server.port=0`
2014-04-23 16:42:10 +08:00
and then inject the actual (``local'') port as a `@Value`. For example:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleDataJpaApplication.class)
@WebApplication
@IntegrationTest("server.port:0")
public class CityRepositoryIntegrationTests {
@Autowired
EmbeddedWebApplicationContext server;
2014-04-23 16:42:10 +08:00
@Value("${local.server.port}")
int port;
// ...
}
----
2014-04-23 16:42:10 +08:00
[[howto-configure-tomcat]]
=== Configure Tomcat
Generally you can follow the advice from
'<<howto-discover-build-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`.
[[howto-terminate-ssl-in-tomcat]]
=== Terminate SSL in Tomcat
Use an `EmbeddedServletContainerCustomizer` and in that add a `TomcatConnectorCustomizer`
that sets up the connector to be secure:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new MyCustomizer();
}
// ...
private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer factory) {
if(factory instanceof TomcatEmbeddedServletContainerFactory) {
customizeTomcat((TomcatEmbeddedServletContainerFactory) factory));
}
}
public void customizeTomcat(TomcatEmbeddedServletContainerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setPort(serverPort);
connector.setSecure(true);
connector.setScheme("https");
connector.setAttribute("keyAlias", "tomcat");
connector.setAttribute("keystorePass", "password");
try {
connector.setAttribute("keystoreFile",
ResourceUtils.getFile("src/ssl/tomcat.keystore").getAbsolutePath());
} catch (FileNotFoundException e) {
throw new IllegalStateException("Cannot load keystore", e);
}
connector.setAttribute("clientAuth", "false");
connector.setAttribute("sslProtocol", "TLS");
connector.setAttribute("SSLEnabled", true);
}
});
}
}
----
[[howto-enable-multiple-connectors-in-tomcat]]
=== Enable Multiple Connectors Tomcat
Add a `org.apache.catalina.connector.Connector` to the
`TomcatEmbeddedServletContainerFactory` which can allow multiple connectors eg a HTTP and
HTTPS connector:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@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);
}
}
----
[[howto-use-jetty-instead-of-tomcat]]
=== Use Jetty instead of Tomcat
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:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<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:
[source,groovy,indent=0,subs="verbatim,quotes,attributes"]
----
configurations {
2014-03-25 21:55:03 +08:00
compile.exclude module: "spring-boot-starter-tomcat"
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.0.0.RC3")
compile("org.springframework.boot:spring-boot-starter-jetty:1.0.0.RC3")
// ...
}
----
[[howto-configure-jetty]]
=== Configure Jetty
Generally you can follow the advice from
'<<howto-discover-build-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`.
[[howto-use-tomcat-8]]
=== Use Tomcat 8
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:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<properties>
<tomcat.version>8.0.3</tomcat.version>
</properties>
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
...
</dependencies>
----
2014-03-26 05:33:11 +08:00
change the classpath to use Tomcat 8 for it to work.
[[howto-use-jetty-9]]
=== Use Jetty 9
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:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<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>
----
[[howto-spring-mvc]]
== Spring MVC
[[howto-write-a-json-rest-service]]
=== Write a JSON REST service
Any Spring `@RestController` in a Spring Boot application should render JSON response by
default as long as Jackson2 is on the classpath. For example:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@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 (but by default only if `MyThing` was
a JAXB object) because browsers tend to send accept headers that prefer XML.
2014-04-23 16:42:10 +08:00
[[howto-write-an-xml-rest-service]]
=== Write an XML REST service
Since JAXB is in the JDK the same example as we used for JSON would work, as long as the
`MyThing` was annotated as `@XmlRootElement`:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
2014-04-23 16:42:10 +08:00
@XmlRootElement
public class MyThing {
2014-04-23 16:42:10 +08:00
private String name;
// .. getters and setters
}
----
2014-04-23 16:42:10 +08:00
To get the server to render XML instead of JSON you might have to send an
`Accept: text/xml` header (or use a browser).
[[howto-customize-the-jackson-objectmapper]]
=== Customize the Jackson ObjectMapper
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 a default
converter with a vanilla `ObjectMapper`. Spring Boot has some features to make it easier
to customize this behavior.
The smallest change that might work is to just add beans of type
`com.fasterxml.jackson.databind.Module` to your context. They will be registered with the
default `ObjectMapper` and then injected into the default message converter. To replace
the default `ObjectMapper` completely, define a `@Bean` of that type and mark it as
`@Primary`.
In addition, if your context contains any beans of type `ObjectMapper` then all of the
`Module` beans will be registered with all of the mappers. So there is 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 '<<howto-customize-the-responsebody-rendering>>' section and the
{sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`WebMvcAutoConfiguration`]
source code for more details.
[[howto-customize-the-responsebody-rendering]]
=== Customize the @ResponseBody rendering
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.
[[howto-switch-off-the-spring-mvc-dispatcherservlet]]
=== Switch off the Spring MVC DispatcherServlet
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).
[[howto-switch-off-default-mvc-configuration]]
=== Switch off the Default MVC configuration
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.
[[howto-customize-view-resolvers]]
=== Customize ViewResolvers
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 the `DefaultServlet` (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 via
`spring.view.prefix` and `spring.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 the `View` being
resolved. It can be overridden by providing a bean of the same type, but it's unlikely
you will need to do that.
* A `ContentNegotiatingViewResolver` with id ``viewResolver'' is only added if there *are*
actually beans of type `View` 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
https://spring.io/blog/2013/06/03/content-negotiation-using-views[blog about `ContentNegotiatingViewResolver`]
that you might like to study to learn more, and also look at the source code for detail.
You can switch off the auto-configured
`ContentNegotiatingViewResolver` 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 to `spring.thymeleaf.prefix` and
`spring.thymeleaf.suffix`, defaults ``classpath:/templates/'' and ``.html''
respectively). It can be overridden by providing a bean of the same name.
Checkout {sc-spring-boot-autoconfigure}/web/WebMvcAutoConfiguration.{sc-ext}[`WebMvcAutoConfiguration`]
and {sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[`ThymeleafAutoConfiguration`]
[[howto-logging]]
== Logging
[[howto-configure-logback-for-loggin]]
=== Configure Logback for logging
Spring Boot has no mandatory logging dependence, except for the `commons-logging` API, of
which there are many implementations to choose from. To use http://logback.qos.ch[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:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
----
2014-03-19 02:26:15 +08:00
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. So 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.
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<?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}` if `logging.file` was set in Boot's external configuration.
* `${LOG_PATH}` if `logging.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).
[[howto-configure-log4j-for-logging]]
=== Configure Log4j for logging
2014-03-16 07:02:20 +08:00
Spring Boot supports http://logging.apache.org/log4j[Log4j] for logging
configuration, but it has to be on the classpath. If you are using the starter poms for
assembling dependencies that means you have to exclude logback and then include log4j
instead. If you aren't using the starter poms then you need to provide `commons-logging`
(at least) in addition to Log4j.
The simplest path to using Log4j is probably through the starter poms, even though it
requires some jiggling with excludes, e.g. in Maven:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<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>${project.groupId}</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
----
NOTE: The use of the log4j starter gathers together the dependencies for common logging
requirements (e.g. including having Tomcat use `java.util.logging` but configure the
output using Log4j). See the Actuator Log4j Sample for more detail and to see it in
action.
[[howto-data-access]]
== Data Access
[[howto-configure-a-datasource]]
=== Configure a DataSource
To override the default settings just define a `@Bean` of your own of type `DataSource`.
See '<<spring-boot-features.adoc#boot-features-configure-datasource>>' in the
``Spring Boot features'' section and the
{sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[`DataSourceAutoConfiguration`]
class for more details.
[[howto-use-spring-data-repositories]]
=== Use Spring Data repositories
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).
[[howto-separate-entity-definitions-from-spring-configuration]]
=== Separate @Entity definitions from Spring configuration
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.
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@Configuration
@EnableAutoConfiguration
@EntityScan(basePackageClasses=City.class)
public class Application {
//...
}
----
[[howto-configure-jpa-properties]]
=== Configure JPA properties
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:
[indent=0,subs="verbatim,quotes,attributes"]
----
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.
2014-04-07 12:44:20 +08:00
[[howto-use-custom-entity-manager]]
=== Use a custom EntityManagerFactory
2014-04-07 12:44:20 +08:00
To take full control of the configuration of the `EntityManagerFactory`, you need to add
a `@Bean` named "entityManagerFactory". To avoid eager initialization of JPA
infrastructure, Spring Boot auto-configuration does not switch on its entity manager
based on the presence of a bean of that type. Instead it has to do it by name.
[[howto-use-traditional-persistence-xml]]
=== Use a traditional persistence.xml
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
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java[`JpaBaseConfiguration`]
for the default settings.
[[howto-database-initialization]]
== Database initialization
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.
[[howto-initialize-a-database-using-jpa]]
=== Initialize a database using JPA
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.
[[howto-initialize-a-database-using-hibernate]]
=== Initialize a database using Hibernate
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).
[[howto-intialize-a-database-using-spring-jdbc]]
=== Initialize a database using Spring JDBC
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 a file `schema-${platform}.sql` where
2014-04-23 16:42:10 +08:00
`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.
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.
[[howto-initialize-a-spring-batch-database]]
=== Initialize a Spring Batch database
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`.
[[howto-use-a-higher-level-database-migration-tool]]
=== Use a higher level database migration tool
Spring Boot works fine with higher level migration tools http://flywaydb.org/[Flyway]
(SQL-based) and http://www.liquibase.org/[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.
[[howto-batch-applications]]
== Batch applications
[[howto-execute-spring-batch-jobs-on-startup]]
=== Execute Spring Batch jobs on startup
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
https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/annotation/EnableBatchProcessing.java[@EnableBatchProcessing]
for more details.
[[howto-actuator]]
== Actuator
[[howto-change-the-http-port-or-address-of-the-actuator-endpoints]]
=== Change the HTTP port or address of the actuator endpoints
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#production-ready-customizing-management-server-port>>'
in the ``Production-ready features'' section.
[[howto-customize-the-whitelabel-error-page]]
=== Customize the ``whitelabel'' error page
The Actuator 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. If you are using
Thymeleaf you can do this by adding an `error.html` 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-actuator}/autoconfigure/ErrorMvcAutoConfiguration.{sc-ext}[`ErrorMvcAutoConfiguration`] for more options.
[[howto-security]]
== Security
[[howto-switch-off-spring-boot-security-configuration]]
=== Switch off the Spring Boot security configuration
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-security,Common application properties>>.
[[howto-change-the-authenticationmanager-and-add-user-accounts]]
=== Change the AuthenticationManager and add user accounts
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.
http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-authentication[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.
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@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
}
----
2014-04-07 12:44:20 +08:00
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.
[[howto-enable-https]]
=== Enable HTTPS
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 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.
[source,properties,indent=0]
----
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`.
[[howto-hotswapping]]
== Hot swapping
[[howto-reload-static-content]]
=== Reload static content
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
<<build-tool-plugins.adoc#build-tool-plugins, 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.
[[howto-reload-thymeleaf-content]]
=== Reload Thymeleaf templates without restarting the container
If you are using Thymeleaf, then set `spring.thymeleaf.cache` to `false`. See
{sc-spring-boot-autoconfigure}/thymeleaf/ThymeleafAutoConfiguration.{sc-ext}[`ThymeleafAutoConfiguration`]
for other template customization options.
[[howto-reload-java-classes-without-restarting]]
=== Reload Java classes without restarting the container
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.
https://github.com/spring-projects/spring-loaded[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).
[[howto-build]]
== Build
[[howto-customize-dependency-versions-with-maven]]
=== Customize dependency versions with Maven
If you use a Maven build that inherits from `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-dependencies`]
POM for a complete list of properties. For example, to pick a different `slf4j` version
you would add the following:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<properties>
<slf4j.version>1.7.5<slf4j.version>
</properties>
----
WARNING: Each Spring Boot release is designed and tested against a specific set of
third-party dependencies. Overriding versions may cause compatibilty issues.
2014-04-24 06:09:53 +08:00
[[howto-remote-debug-maven-run]]
=== Remote debug a Spring Boot application started with Maven
To attach a remote debugger to a Spring Boot application started with Maven you can use
the `mvnDebug` command rather than `mvn`. For example:
[indent=0]
----
$ mvnDebug spring-boot:run
----
You can now attach a remote debugger to your running application on port `8000`.
[[howto-build-an-executable-archive-with-ant]]
=== Build an executable archive with Ant
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 a `Start-Class`.
. Add the runtime dependencies in a nested "lib" directory (for a jar) and the
`provided` (embedded container) dependencies in a nested `lib-provided` directory.
Remember *not* to compress the entries in the archive.
. Add the `spring-boot-loader` classes at the root of the archive (so the `Main-Class`
is available).
Example:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<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
[indent=0,subs="verbatim,quotes,attributes"]
----
$ ant -lib <path_to>/ivy-2.2.jar
----
after which you can run the application with
[indent=0,subs="verbatim,quotes,attributes"]
----
$ java -jar target/*.jar
----
[[howto-traditional-deployment]]
== Traditional deployment
[[howto-create-a-deployable-war-file]]
=== Create a deployable war file
Use the `SpringBootServletInitializer` base class, which is picked up by Spring's
Servlet 3.0 support on deployment. Add an extension of that to your project and build a
war file as normal. For more detail, see the
http://spring.io/guides/gs/convert-jar-to-war[``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].
[[howto-create-a-deployable-war-file-for-older-containers]]
=== Create a deployable war file for older servlet containers
Older Servlet containers don't have support for the `ServletContextInitializer` bootstrap
process used in Servlet 3.0. You can still use Spring and Spring Boot in these containers
but you are going to need to add a `web.xml` to your application and configure it to load
an `ApplicationContext` via a `DispatcherServlet`.
[[howto-convert-an-existing-application-to-spring-boot]]
=== Convert an existing application to Spring Boot
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 http://spring.io/guides/gs/convert-jar-to-war/[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:
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
@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
2014-03-14 23:31:57 +08:00
`/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 type `Servlet` or `ServletRegistrationBean` installs that bean in the
container as if it was a `<servlet/>` and `<servlet-mapping/>` in `web.xml`.
* A `@Bean` of type `Filter` or `FilterRegistrationBean` behaves similarly (like a
`<filter/>` and `<filter-mapping/>`.
* An `ApplicationContext` in an XML file can be added to an `@Import` in your
`Application`. 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.
[source,java,indent=0,subs="verbatim,quotes,attributes"]
----
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
<<howto-build-an-application-context-hierarchy, 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.