73. Embedded servlet containers

73.1 Add a Servlet, Filter or Listener to an application

There are two ways to add ServletFilterServletContextListener and the other listeners supported by the Servlet spec to your application. You can either provide Spring beans for them, or enable scanning for Servlet components.

73.1.1 Add a Servlet, Filter or Listener using a Spring bean

To add a ServletFilter, or Servlet *Listener provide a @Bean definition for it. This can be very useful when you want to inject configuration or dependencies. However, you must 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 ServletRegistrationBeaninstead of or as well as the underlying component.

If no dispatcherType is specified on a filter registration, it will match FORWARD,INCLUDE and REQUEST. If async has been enabled, it will match ASYNCas well.

If you are migrating a filter that has no dispatcher element in web.xml you will need to specify a dispatcherType yourself:

@Bean
public FilterRegistrationBean myFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
.... return registration;
}

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

73.1.2 Add Servlets, Filters, and Listeners using classpath scanning

@WebServlet@WebFilter, and @WebListener annotated classes can be automatically registered with an embedded servlet container by annotating a @Configuration class with @ServletComponentScan and specifying the package(s) containing the components that you want to register. By default, @ServletComponentScan will scan from the package of the annotated class.

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

73.3 Use a random unassigned HTTP port

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

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

Tests that use @SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) can also inject the actual port into a field using the @LocalServerPortannotation. For example:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class MyWebIntegrationTests { @Autowired
EmbeddedWebApplicationContext server; @LocalServerPort
int port; // ... }

@LocalServerPort is a meta-annotation for @Value("${local.server.port}"). Don’t try to inject the port in a regular application. As we just saw, the value is only set once the container has initialized; contrary to a test, application code callbacks are processed early (i.e. before the value is actually available).

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

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.

73.6 Configure Access Logging

Access logs can be configured for Tomcat and Undertow via their respective namespaces.

For instance, the following logs access on Tomcat with a custom pattern.

server.tomcat.basedir=my-tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)

The default location for logs is a logs directory relative to the tomcat base dir and said directory is a temp directory by default so you may want to fix Tomcat’s base directory or use an absolute path for the logs. In the example above, the logs will be available in my-tomcat/logs relative to the working directory of the application.

Access logging for undertow can be configured in a similar fashion

server.undertow.accesslog.enabled=true
server.undertow.accesslog.pattern=%t %a "%r" %s (%D ms)

Logs are stored in a logs directory relative to the working directory of the application. This can be customized via server.undertow.accesslog.directory.

73.7 Use behind a front-end proxy server

Your application might need to send 302 redirects or render content with absolute links back to itself. When running behind a proxy, the caller wants a link to the proxy, and not to the physical address of the machine hosting your app. Typically such situations are handled via a contract with the proxy, which will add headers to tell the back end how to construct links to itself.

If the proxy adds conventional X-Forwarded-For and X-Forwarded-Proto headers (most do this out of the box) the absolute links should be rendered correctly as long as server.use-forward-headers is set to true in your application.properties.

If your application is running in Cloud Foundry or Heroku the server.use-forward-headers property will default to true if not specified. In all other instances it defaults to false.

73.7.1 Customize Tomcat’s proxy configuration

If you are using Tomcat you can additionally configure the names of the headers used to carry “forwarded” information:

server.tomcat.remote-ip-header=x-your-remote-ip-header
server.tomcat.protocol-header=x-your-protocol-header

Tomcat is also configured with a default regular expression that matches internal proxies that are to be trusted. By default, IP addresses in 10/8192.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}

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

You can trust all proxies by setting the internal-proxies to empty (but don’t do this in production).

You can take complete control of the configuration of Tomcat’s RemoteIpValve by switching the automatic one off (i.e. set server.use-forward-headers=false) and adding a new valve instance in a TomcatEmbeddedServletContainerFactory bean.

73.8 Configure Tomcat

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

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

73.10 Use Tomcat’s LegacyCookieProcessor

The embedded Tomcat used by Spring Boot does not support "Version 0" of the Cookie format out of the box, and you may see the following error:

java.lang.IllegalArgumentException: An invalid character [32] was present in the Cookie value

If at all possible, you should consider updating your code to only store values compliant with later Cookie specifications. If, however, you’re unable to change the way that cookies are written, you can instead configure Tomcat to use a LegacyCookieProcessor. To switch to the LegacyCookieProcessor use anEmbeddedServletContainerCustomizer bean that adds a TomcatContextCustomizer:

@Bean
public EmbeddedServletContainerCustomizer cookieProcessorCustomizer() {
return new EmbeddedServletContainerCustomizer() { @Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addContextCustomizers(new TomcatContextCustomizer() { @Override
public void customize(Context context) {
context.setCookieProcessor(new LegacyCookieProcessor());
} });
}
} };
}

73.11 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.5.3.RELEASE")
compile("org.springframework.boot:spring-boot-starter-jetty:1.5.3.RELEASE")
// ...
}

73.12 Configure Jetty

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

73.13 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.5.3.RELEASE")
compile("org.springframework.boot:spring-boot-starter-undertow:1.5.3.RELEASE")
// ...
}

73.14 Configure Undertow

Generally you can follow the advice from Section 72.8, “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 theUndertowEmbeddedServletContainerFactory you can use an UndertowBuilderCustomizer to modify Undertow’s configuration to meet your needs. Or the nuclear option is to add your own UndertowEmbeddedServletContainerFactory.

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

73.16 Use Tomcat 7.x or 8.0

Tomcat 7 & 8.0 work with Spring Boot, but the default is to use Tomcat 8.5. If you cannot use Tomcat 8.5 (for example, because you are using Java 1.6) you will need to change your classpath to reference a different version.

73.16.1 Use Tomcat 7.x or 8.0 with Maven

If you are using the starters and parent you can change the Tomcat version property and additionally import tomcat-juli. 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>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
...
</dependencies>

73.16.2 Use Tomcat 7.x or 8.0 with Gradle

With Gradle, you can change the Tomcat version by setting the tomcat.version property and then additionally include tomcat-juli:

ext['tomcat.version'] = '7.0.59'
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile group:'org.apache.tomcat', name:'tomcat-juli', version:property('tomcat.version')
}

73.17 Use Jetty 9.2

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

73.17.1 Use Jetty 9.2 with Maven

If you are using the starters and parent you can just add the Jetty starter and override the jetty.version property:

<properties>
<jetty.version>9.2.17.v20160517</jetty.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>

73.17.2 Use Jetty 9.2 with Gradle

You can set the jetty.version property. For example, for a simple webapp or service:

ext['jetty.version'] = '9.2.17.v20160517'
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')
}

73.18 Use Jetty 8

Jetty 8 works with Spring Boot, but the default is to use Jetty 9.3. If you cannot use Jetty 9.3 (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.

73.18.1 Use Jetty 8 with Maven

If you are using the starters 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>

73.18.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'
}
}

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

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

https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-embedded-servlet-containers

Embedded servlet containers的更多相关文章

  1. Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containers

    原文地址:https://examples.javacodegeeks.com/enterprise-java/spring/tomcat-vs-jetty-vs-undertow-compariso ...

  2. 1.端口被占用问题:Embedded servlet container failed to start. Port 8097 was already in use.

    1.端口被占用问题:Embedded servlet container failed to start. Port 8097 was already in use.netstat -anonetst ...

  3. SpringBoot 配置 Servlet、Filter、Listener

    SpringBoot 配置 Servlet.Filter.Listener 在SpringBoot应用中,嵌入式的 Servlet 3.0+ 容器不会直接使用 ServletContainerInit ...

  4. spring mvc DispatcherServlet详解之前传---FrameworkServlet

    做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...

  5. 深入学习微框架:Spring Boot - NO

    http://blog.csdn.net/hengyunabc/article/details/50120001 Our primary goals are: Provide a radically ...

  6. 40. Testing Prev Part IV. Spring Boot features

    40. Testing Spring Boot provides a number of utilities and annotations to help when testing your app ...

  7. spring-boot(三) HowTo

    Spring Boot How To 1. 简介 本章节将回答一些常见的"我该怎么做"类型的问题,这些问题在我们使用spring Boot时经常遇到.这绝不是一个详尽的列表,但它覆 ...

  8. SpringBoot 之 MVC

    SpringBoot MVC 和静态资源 首先,我们一定要搞清楚,mvc 配置和 static 配置的联系和区别. mvc 配置其实就是给 spring mvc 框架用的, 具体来说, 比如 @Req ...

  9. Spring Boot 容器选择 Undertow 而不是 Tomcat

    Spring Boot 内嵌容器Undertow参数设置 配置项: # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 # 不要设置过大,如果过大,启动 ...

随机推荐

  1. OpenCV 透视变换实例

    参考文献: http://www.cnblogs.com/self-control/archive/2013/01/18/2867022.html http://opencv-code.com/tut ...

  2. iOS雷达图 iOS RadarChart实现

    实现效果 刚拿到设计稿的时候大概看了一眼,当时心里想着放张背景图,然后计算下相应点的坐标,在最上面画一层就OK了,其实一开始实现的时候也确实是这么做的,然后我就日了狗了,发现设计稿上多层五边形的间隔不 ...

  3. Spring--ApplicationContext

    //中心接口,给应用提供配置信息 public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory ...

  4. JAVA_Lock

    今天是毕业入职的第一个周末,一直对多线程并发方面的知识比较感兴趣,因为目前我手里的项目并没有涉及到并发方面的知识,所以怕以后遗忘,也便于以后复习和使用,所以总结了一下Lock里面的一些类的方法.具体的 ...

  5. CDH安装系统环境准备——系统版本和安装包下载地址指南

    由于Hadoop深受客户欢迎,许多公司都推出了各自版本的Hadoop,也有一些公司则围绕Hadoop开发产品.在Hadoop生态系统中,规模最大.知名度最高的公司则是Cloudera.接下来的日子里, ...

  6. angularjs学习笔记之一

    directive 通过AngularJS模块API中的.directive()方法,我们可以通过传入一个字符串和一个函数来 注册一个新指令.其中字符串是这个指令的名字,指令名应该是驼峰命名风格的,函 ...

  7. PLSQL 创建自定义函数注意事项

    2017-6-8周四,今天遇到的需求是,从数据库中查找出某张表的某些数据,并将这些数据做简单的加减运算再得到结果集,没有思路,后来问辉哥,给我的建议是给这些运算封装成一个SQL函数,select选择字 ...

  8. openssh升级的坑爹之路

    安装Zlib http://zlib.net/zlib-1.2.8.tar.gz tar -zxvf zlib-1.2.8.tar.gz cd zlib-1.2.8 ./configure --sha ...

  9. Mysql系列-数据库

    一 .数据库管理软件的由来 基于我们之前所学,数据要想永久保存,都是保存于文件中,毫无疑问,一个文件仅仅只能存在于某一台机器上. 如果我们暂且忽略直接基于文件来存取数据的效率问题,并且假设程序所有的组 ...

  10. AttributeError: module 'enum' has no attribute 'IntFlag'

    Mac PyCharm新建以Python3.6.1为解释器的Django项目的时候出现以下错误提示: AttributeError: module 'enum' has no attribute 'I ...