首页 > 其他分享 >Embedded servlet containers

Embedded servlet containers

时间:2022-12-19 11:00:33浏览次数:58  
标签:tomcat Embedded spring boot Tomcat containers org servlet starter

73. Embedded servlet containers

73.1 Add a Servlet, Filter or Listener to an application

There are two ways to add ​​Servlet​​​, ​​Filter​​​, ​​ServletContextListener​​ 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 ​​Servlet​​​, ​​Filter​​​, 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 ​​ServletRegistrationBean​​instead 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 ​​ASYNC​​as 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 ​​@LocalServerPort​​annotation. 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/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}


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 an​​EmbeddedServletContainerCustomizer​​​ 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 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​​.

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​

 



标签:tomcat,Embedded,spring,boot,Tomcat,containers,org,servlet,starter
From: https://blog.51cto.com/u_15147537/5951564

相关文章

  • 3、梳理DispatcherServlet核心功能!
    今天梳理一下DispatcherServlet的组成结构,了解其各个核心功能。DispatcherServlet只是一个普通的Servlet,它也会接收JavaWeb服务器的request和response参数,从request中......
  • 2、Spring MVC是一个Servlet!
    昨天学习了JavaWeb服务器是如何处理请求的,可以知道服务器会将请求交给Servlet处理。简单来说,JavaWeb服务器是一个接收HTTP请求的应用软件。就好比在手机代办事项里创建......
  • Servlet注解,简化配置
    Servlet注解,简化配置分析OA项目中的web.xml文件一个简单的servlet的CRUD中web.xml文件的配置信息就如此之多,如果采用该方式,对于一个项目来说,web.xml文件会非常庞大,有......
  • Servlet多线程
    Servlet体系结构是建立在Java多线程机制之上的,它的生命周期是由Web容器负责的。当客户端第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件实例化这个Servlet类......
  • servlet的url-pattern匹配规则
     目录​​1url-pattern匹配规则说明​​​​2四种匹配规则优先顺序​​​​2.1 精确匹配​​​​2.2路径匹配​​​​2.3扩展名匹配​​​​2.4缺省匹配​​​​3需......
  • Servlet_概述与Servlet_快速入门
    Servlet_概述Servlet:  server  applet概念:运行在服务器端的小程序 Servlet就是一个接......
  • 关于对ServletContext对象的应用详解
    一.预准备工程1.1ServletContext的概念ServletContext是用于存储信息的全局空间。它从服务器开始就存在,只有在服务器关闭后才释放。ServletContext和Cookie、Session对......
  • 对于Servlet原理以及Mapping的五种映射和404页面的详解
    一.Servlet原理1,浏览器向web容器发送Http请求,我们这里用的web容器为tomcat。2.我们在Servlet里的protectedvoiddoGet(HttpServletRequestreq,HttpServletResponsere......
  • Servlet原理
    Servlet的本质是一个Java接口,定义了一套处理网络请求的规范。最主要的是两个生命周期方法init()和destory(),以及一个处理请求的service()。因为处理一个网络请求,绕不开:初......
  • Cannot invoke “org.springframework.web.servlet.mvc.condition.PatternsRequestCon
    异常信息:Cannotinvoke“org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()”because“this.condition”isnull出现该异常......