67. Embedded servlet containers

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

67.2 Disable registration of a Servlet or Filter

As described above any Servlet or Filter beans will be registered with the servlet container automatically. To disable registration of a particular Filter or Servlet bean create a registration bean for it and mark it as disabled. For example:

@Bean
public FilterRegistrationBean registration(MyFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

67.3 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 Section 27.3.3, “Customizing embedded servlet containers” in the ‘Spring Boot features’ section, or the ServerProperties source code.

67.4 Use a random unassigned HTTP port

To scan for a free port (using OS natives to prevent clashes) use server.port=0.

[Tip]Tip

You can know what port got allocated at runtime by looking at the local.server.port property in the Environment.

67.5 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 useful practice for use with @WebIntegrationTests 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)
@WebIntegrationTest("server.port:0")
public class CityRepositoryIntegrationTests {

    @Autowired
    EmbeddedWebApplicationContext server;

    @Value("${local.server.port}")
    int port;

    // ...

}

67.6 Configure SSL

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 Ssl for details of all of the supported properties.

[Note]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. This limitation doesn’t apply to Jetty and Undertow.

Using configuration like the example above means the application will no longer support plain HTTP connector at port 8080. Spring Boot doesn’t support the configuration of both an HTTP connector and an HTTPS connector via application.properties. If you want to have both then you’ll need to configure one of them programmatically. It’s recommended to use application.properties to configure HTTPS as the HTTP connector is the easier of the two to configure programmatically. See the spring-boot-sample-tomcat-multi-connectors sample project for an example.

67.7 Configure Tomcat

Generally you can follow the advice from Section 66.7, “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.

67.8 Enable Multiple Connectors with Tomcat

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);
    }
}

67.9 Use Tomcat behind a front-end proxy server

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-proto

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}
[Note]Note

The double backslashes are only required when you’re using a properties file for configuration. If you are using YAML, single backslashes are sufficient and a value that’s equivalent to the one shown above would be 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.

67.10 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:

<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:1.3.0.M2")
    compile("org.springframework.boot:spring-boot-starter-jetty:1.3.0.M2")
    // ...
}

67.11 Configure Jetty

Generally you can follow the advice from Section 66.7, “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.

67.12 Use Undertow instead of Tomcat

Using Undertow instead of Tomcat is very similar to using Jetty instead of Tomcat. You need to exclude the Tomcat dependencies and include the Undertow starter instead.

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-undertow</artifactId>
</dependency>

Example in Gradle:

configurations {
    compile.exclude module: "spring-boot-starter-tomcat"
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:1.3.0.M2")
    compile("org.springframework.boot:spring-boot-starter-undertow:1.3.0.M2")
    // ...
}

67.13 Configure Undertow

Generally you can follow the advice from Section 66.7, “Discover built-in options for external properties” about @ConfigurationProperties (ServerProperties and ServerProperties.Undertow are the main ones here), but also look at EmbeddedServletContainerCustomizer. Once you have access to the UndertowEmbeddedServletContainerFactory you can use an UndertowBuilderCustomizer to modify Undertow’s configuration to meet your needs. Or the nuclear option is to add your own UndertowEmbeddedServletContainerFactory.

67.14 Enable Multiple Listeners with Undertow

Add an UndertowBuilderCustomizer to the UndertowEmbeddedServletContainerFactory and add a listener to the Builder:

@Bean
public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() {
    UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
    factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {

        @Override
        public void customize(Builder builder) {
            builder.addHttpListener(8080, "0.0.0.0");
        }

    });
    return factory;
}

67.15 Use Tomcat 7

Tomcat 7 works with Spring Boot, but the default is to use Tomcat 8. If you cannot use Tomcat 8 (for example, because you are using Java 1.6) you will need to change your classpath to reference Tomcat 7 .

67.15.1 Use Tomcat 7 with Maven

If you are using the starter poms and parent you can just change the Tomcat version property, e.g. for a simple webapp or service:

<properties>
    <tomcat.version>7.0.59</tomcat.version>
</properties>
<dependencies>
    ...
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    ...
</dependencies>

67.15.2 Use Tomcat 7 with Gradle

You can change the Tomcat version by setting the tomcat.version property:

ext['tomcat.version'] = '7.0.59'
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
}

67.16 Use Jetty 8

Jetty 8 works with Spring Boot, but the default is to use Jetty 9. If you cannot use Jetty 9 (for example, because you are using Java 1.6) you will need to change your classpath to reference Jetty 8. You will also need to exclude Jetty’s WebSocket-related dependencies.

67.16.1 Use Jetty 8 with Maven

If you are using the starter poms and parent you can just add the Jetty starter with the required WebSocket exclusion and change the version properties, e.g. for a simple webapp or service:

<properties>
    <jetty.version>8.1.15.v20140411</jetty.version>
    <jetty-jsp.version>2.2.0.v201112011158</jetty-jsp.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>
        <exclusions>
            <exclusion>
                <groupId>org.eclipse.jetty.websocket</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

67.16.2 Use Jetty 8 with Gradle

You can set the jetty.version property and exclude the WebSocket dependency, e.g. for a simple webapp or service:

ext['jetty.version'] = '8.1.15.v20140411'
dependencies {
    compile ('org.springframework.boot:spring-boot-starter-web') {
        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
    }
    compile ('org.springframework.boot:spring-boot-starter-jetty') {
        exclude group: 'org.eclipse.jetty.websocket'
    }
}

67.17 Create WebSocket endpoints using @ServerEndpoint

If you want to use @ServerEndpoint in a Spring Boot application that used an embedded container, you must declare a single ServerEndpointExporter @Bean:

@Bean
public ServerEndpointExporter serverEndpointExporter() {
    return new ServerEndpointExporter();
}

This bean will register any @ServerEndpoint annotated beans with the underlying WebSocket container. When deployed to a standalone servlet container this role is performed by a servlet container initializer and the ServerEndpointExporter bean is not required.

67.18 Enable HTTP response compression

HTTP response compression is supported by Jetty, Tomcat, and Undertow. It can be enabled via application.properties:

server.compression.enabled=true

By default, responses must be at least 2048 bytes in length for compression to be performed. This can be configured using the server.compression.min-response-size property.

By default, responses will only be compressed if their content type is one of the following:

  • text/html
  • text/xml
  • text/plain
  • text/css

This can be configured using the server.compression.mime-types property.