Skip to content

Commit

Permalink
More howtos
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave Syer committed Nov 27, 2013
1 parent d3ff4f5 commit f685344
Showing 1 changed file with 291 additions and 2 deletions.
293 changes: 291 additions & 2 deletions docs/docs/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,300 @@ HOWTO guides. If you want to add a placeholder for a question without
an answer, put it at the top (at header level 2) and we can fill in
the gaps later.

There is a really useful `AutoConfigurationReport` available in any
Spring Boot `ApplicationContext`. You will see it automatically if a
context fails to start, and also if you enable DEBUG logging for
Spring Boot. If you use the Actuator there is also an endpoint
`/autoconfig` 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
Javadocs. 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. In those clases...

* Look for classes that are `@ConfigurationProperties`
(e.g. [`ServerProperties`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java?source=c))
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
`name="server"` and its configuration properties are `server.port`,
`server.address` etc.

* 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
placeholders resolved from the `Environment`.

## Configure Tomcat

## Configure Jetty

<span id="build.hierarchy"/>
## Build an ApplicationContext Hierarchy (Adding a Parent or Root Context)

The
[`SpringApplicationBuilder`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java)
has methods specifically designed for the purpose of building a
hierarchy, e.g.

```java
SpringApplicationBuilder application = new SpringApplicationBuilder();
application.sources(Parent.class).child(Application.class).run(args);
```

There are some restrictions, e.g. the parent aplication context is
*not* a `WebApplicationContext`. Both parent and child are executed
with the same `Environment` constructed in the usual way to include
command line arguments. Any `ServletContextAware` components all have
to go in the child context, otherwise there is no way for Spring Boot
to create the `ServletContext` in time.

## 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
[Getting Started Guide on Converting a JAR to a WAR](http://spring.io/guides/gs/convert-jar-to-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-INFO/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.

```java
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 and
* Those 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
squish 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](#build.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.


## Serve Static Content

Spring Boot by default will serve static content from a folder called
`/static` (or `/public` or or `/resources` or `/META-INF/resources`)
in the classpath or from the root of the `ServeltContext`. It uses
the `ResourceHttpRequestHandler` from Spring MVC so you can modify
that behaviour by adding your own `WebMvcConfigurerAdapter` and
overriding the `addResourceHandlers` method.

By default in a standalone web application the default servlet from
the container is also enabled, and acts as a fallback, serving content
from the root of the `ServletContext` if Spring decides not to handle
it. Most of the time this will not happen unless you modify the
deafult MVC configuration because Spring will always be able to handle
requests through the `DispatcherServlet`.

In addition to the 'standard' static resource locations above, a
special case is made for
[Webjars content](http://www.webjars.org/). Any resources with a path
in `/webjars/**` will be served from jar files if they are packaged in
the Webjars format.

For more detail look at the
[`WebMvcAutoConfiguration`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration.java?source=c)
source code.

## 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 scan for a free port (using OS natives to prevent clashes) use
`server.port=0`. To switch off the HTTP endpoints completely, but
still create a `WebApplicationContext`, use `server.port=-1` (this is
sometimes useful for testing).

For more detail look at the
[`ServerProperties`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java?source=c)
source code.

## 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
[`ManagementServerProperties`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/properties/ManagementServerProperties.java?source=c)
source code.

## 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.

```properties
server.port: ${port:8080}
```

> Note that 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.
## Test a Spring Boot Application

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

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

@Autowired
CityRepository repository;

...
```

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

<span id="main.properties"/>
## Externalize the Configuration of SpringApplication

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

```properties
spring.main.web_environment: false
spring.main.show_banner: false
```

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

## Create a Non-Web Application

## Create a Deployable WAR File?
Not all Spring applications have to be web applications (or web
services). If you want to execute some code in a `main` method, but
also bootstrap a Spring application to set up the infrastructure to
use, then it's easy with the `SpringApplication` features of Spring
Boot. A `SpringApplication` changes its `ApplicationContext` class
depending on whether it thinks it needs a web application or not. The
first thing you can do to help it is to just leave the web
depdendencies off the classpath. If you can't do that (e.g. you are
running 2 applications from the same code base) then you can
explicitly call `SpringApplication.setWebEnvironment(false)`, or set
the `applicationContextClass` property (through the Java API or with
[external properties](#main.properties)). Application code that you
want to run as your business logic can be implemented as a
`CommandLineRunner` and dropped into the context as a `@Bean`
definition.

## Create a Deployable WAR File

Use the `SpringBootServletInitializer` base class, which is picked up
by Spring's Servlet 3.0 support on deployment. Add an extension of
Expand All @@ -30,7 +319,7 @@ Maven example

[gs-war]: http://spring.io/guides/gs/convert-jar-to-war

## Create a Deployable WAR File for older Servlet 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
Expand Down

0 comments on commit f685344

Please sign in to comment.