Tomcat,Jetty和Undertow:Spring Boot嵌入式Servlet容器的比较

1.源码

随着微服务的普及,我们已经看到带有嵌入式servlet容器的应用的普及也有类似的增长。Spring Boot是基于Java的框架,支持应用程序服务。它可以作为带有嵌入式servlet容器的独立jar或容器内的WAR文件运行。

使用SpringBoot时,首先引人注意的便是其启动方式,我们熟知的web项目都是需要部署到服务容器上,例如tomcat、weblogic、widefly(以前叫JBoss),然后启动web容器真正运行我们的系统。而SpringBoot搭建的系统却是运行***Application.class中的main方法启动。原因是SpringBoot除了高度集成封装了Spring一系列框架之外,还封装了web容器,SpringBoot启动时会根据配置启动相应的上下文环境,查看EmbeddedServletContainerAutoConfiguration源码可知。

@AutoConfigureOrder(-2147483648)
@Configuration
@ConditionalOnWebApplication
@Import({EmbeddedServletContainerAutoConfiguration.BeanPostProcessorsRegistrar.class})
public class EmbeddedServletContainerAutoConfiguration {
    ...
    ...(中间省略部分)

    @Configuration
    @ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})//Undertow配置判断
    @ConditionalOnMissingBean(
        value = {EmbeddedServletContainerFactory.class},
        search = SearchStrategy.CURRENT
    )
    public static class EmbeddedUndertow {
        public EmbeddedUndertow() {
        }

        @Bean
        public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
            return new UndertowEmbeddedServletContainerFactory();
        }
    }

    @Configuration
    @ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})//Jetty配置判断
    @ConditionalOnMissingBean(
        value = {EmbeddedServletContainerFactory.class},
        search = SearchStrategy.CURRENT
    )
    public static class EmbeddedJetty {
        public EmbeddedJetty() {
        }

        @Bean
        public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
            return new JettyEmbeddedServletContainerFactory();
        }
    }

    @Configuration
    @ConditionalOnClass({Servlet.class, Tomcat.class})//Tomcat配置判断,默认为Tomcat
    @ConditionalOnMissingBean(
        value = {EmbeddedServletContainerFactory.class},
        search = SearchStrategy.CURRENT
    )
    public static class EmbeddedTomcat {
        public EmbeddedTomcat() {
        }

        @Bean
        public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
            return new TomcatEmbeddedServletContainerFactory();
        }
    }
}


该自动配置类表明SpringBoot支持封装Tomcat、Jetty和Undertow三种web容器,查看spring-boot-starter-web的pom.xml(如下),其默认配置为Tomcat。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starters</artifactId>
        <version>1.5.8.RELEASE</version>
    </parent>
    <artifactId>spring-boot-starter-web</artifactId>
    <name>Spring Boot Web Starter</name>
    <description>Starter for building web, including RESTful, applications using Spring
        MVC. Uses Tomcat as the default embedded container</description>
    <url>http://projects.spring.io/spring-boot/</url>
    <organization>
        <name>Pivotal Software, Inc.</name>
        <url>http://www.spring.io</url>
    </organization>
    <properties>
        <main.basedir>${basedir}/../..</main.basedir>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        ...
        ...


若我们使用其他容器,该如何配置

Tomcat vs. Jetty vs. Undertow: Comparison of Spring Boot Embedded Servlet Containers详细比较了SpringBoot中三种容器的性能、稳定性等,结果证明了Undertow在性能和内存使用上是最好的。

1.设置Spring Boot应用程序

1.1 Setup Spring Boot Dependencies

默认的嵌入式Servlet容器是Tomcat。 此版本的Spring Web 1.4.3引入了Tomcat版本8.5.6。

pom.xml

01

02

03

04

05

06

07

08

09

10

11

12

13

<parent><font></font>

   <groupId>org.springframework.boot</groupId><font></font>

   <artifactId>spring-boot-starter-parent</artifactId><font></font>

   <version>1.4.3.RELEASE</version><font></font>

</parent><font></font>

<font></font>

<dependencies><font></font>

   <!-- TOMCAT --><font></font>

   <dependency><font></font>

      <groupId>org.springframework.boot</groupId><font></font>

      <artifactId>spring-boot-starter-web</artifactId><font></font>

   </dependency><font></font>

</dependencies><font></font>

1.2设置Spring Boot主要应用程序和控制器
要设置Spring Boot应用程序,您可以在Main类中包含@SpringBootApplication批注。 @SpringBootApplication批注引入了@ SpringBootConfiguration,@ EnableAutoConfiguration和@ComponentScan批注。

Application.java

1

2

3

4

5

6

@SpringBootApplication

@ConfigurationProperties

public class Application {

public static void main(String[] args) {

   SpringApplication.run(Application.class, args);

}

 

You may choose to eliminate this annotation and add the @SpringBootConfiguration alone or to another class that allows you to customize the configuration. The @ComponentScan will scan your application for items like the @Controller you will need to setup a RESTful service. The following controller will return a simple “Hello World” string from a HTTP GET request. We have also included in the bundled example another endpoint mapping that returns a complex object type.

SampleController.java

01

02

03

04

05

06

07

08

09

10

11

@Controller

public class SampleController {

 

@Autowired

private ResourceLoader resourceLoader;

 

@RequestMapping("/")

@ResponseBody

public String home() {

   return "Hello World!";

}

1.3 Key Configuration Parameters

The default properties for all the embedded servlet containers are the same. Some of the most important properties to consider are the properties for configuring startup information like ports and application name, TSL, access logs, compression and many more.

For example, to configure SSL add the following to key value pairs to the application.properties.

application.properties

1

2

3

4

server.port=8443

server.ssl.key-store=classpath:keystore.jks

server.ssl.key-store-password=secret

server.ssl.key-password=another-secret

1.4 How to Find Additional Parameters

To explore the parameters for Spring boot applications you can add the Spring actuator dependency and the @ConfigurationProperties annotation to your Main class. You then visit the /configprops endpoint on your application to get a list of the available properties.

Application.java

1

2

3

@SpringBootApplication

@ConfigurationProperties

public class Application {

pom.xml

1

2

3

4

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

1

http://localhost:8080/jcg/service/configprops

1.5 Change version of Embedded Servlet Containers

The embedded servlet container versions are defined in the following parent dependency from the pom. You can change the version of the embedded servlet container by explicitly including the dependency and identifying a new version in the pom. We will show you how in the examples below.

pom.xml

1

2

3

4

5

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-dependencies</artifactId>

   <version>1.3.7.RELEASE</version>

</dependency>

2. Tomcat

As Tomcat is the default embedded servlet container there is nothing you need to do to the default implementation to use Tomcat. You can change the version of Tomcat you are using or change properties in the pom.xml or application.properties files.

2.2 Change Version of Tomcat

pom.xml

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

<properties><tomcat.version>8.5.6</tomcat.version></properties>

 

<dependency>

   <groupId>org.apache.tomcat.embed</groupId>

   <artifactId>tomcat-embed-core</artifactId>

   <version>${tomcat.version}</version>

</dependency>

<dependency>

   <groupId>org.apache.tomcat.embed</groupId>

   <artifactId>tomcat-embed-el</artifactId>

   <version>${tomcat.version}</version>

</dependency>

<dependency>

   <groupId>org.apache.tomcat.embed</groupId>

   <artifactId>tomcat-embed-websocket</artifactId>

   <version>${tomcat.version}</version>

</dependency>

3. Jetty

To change the embedded servlet container to Jetty you need to edit the pom file to remove the Tomcat dependency and add Jetty.

3.1 Change to Jetty (version 9.3.14)

pom.xml

01

02

03

04

05

06

07

08

09

10

11

12

13

14

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

4. Undertow

To change the embedded servlet container to Undertow you need to edit the pom file to remove the Tomcat dependency and add Undertow.

4.1 Change to Undertow (version 1.3.24 final)

Notice the undertow version included in the spring boot starter is incorrect, referring to 1.3.25. You’ll need to change it to 1.3.24.Final for this to work at the time of this article.

pom.xml

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

<dependency>

   <groupId>io.undertow</groupId>

   <artifactId>undertow-core</artifactId>

   <version>1.3.24.Final</version>

</dependency>

<dependency>

   <groupId>io.undertow</groupId>

   <artifactId>undertow-servlet</artifactId>

   <version>1.3.24.Final</version>

</dependency>

5. Performance and Load

In this example, we will analyze both the peformance of HTTP requests and the memory footprint at startup of all three embedded servlet containers. We used JMeter to measure performance by simulating load and JVisualVM to look at the memory footprint.

5.1 Measure Performance

In this example, we will analyze both the peformance of simple RESTFul GET requests that return a string and more complex GET requests that return complex JSON objects. JMeter is the tool used to measure the performance of the the three different types of containers. The key to setting up this test was establishing thread groups with the appropriate load, a counter to dynamically update the input to the API and report viewers to display or aggregate the results. For the simple string examples, we used a thread group with 1000 threads that would loop 3 times through the sequence. It also used a ramp up time of 10 seconds. For the complex object examples, we used the same parameters but did not loop.

7.结论
数字表明Undertow在性能和内存使用方面是最好的。 令人鼓舞的是,Undertow正在拥抱最新功能并默认使用持久连接。 这些数字并不表示此示例中使用的负载会导致性能出现显着差异,但是我可以想象它们会扩展,并且如果性能是最重要的因素,Undertow将是您的应用程序的正确选择。 考虑到组织的功能,可以合理地认为一个组织可能偏爱嵌入式Servlet容器。 由于应用程序要求(包括性能,内存使用情况和功能),许多默认设置将不得不更改。

连接地址:https://examples.javacodegeeks.com/enterprise-java/spring/tomcat-vs-jetty-vs-undertow-comparison-of-spring-boot-embedded-servlet-containers/

更换内置容器,能提高SpringBoot项目的性能,由于SpringBoot插拔式的模块设计,配置Undertow只需要两步,如下。

1.第一步,去除原容器依赖,加入Undertow依赖。

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


2.第二步,在application.yml中配置Undertow。

server.undertow.accesslog.dir= # Undertow access log directory.
server.undertow.accesslog.enabled=false # Enable access log.
server.undertow.accesslog.pattern=common # Format pattern for access logs.
server.undertow.accesslog.prefix=access_log. # Log file name prefix.
server.undertow.accesslog.rotate=true # Enable access log rotation.
server.undertow.accesslog.suffix=log # Log file name suffix.
server.undertow.buffer-size= # Size of each buffer in bytes.
server.undertow.buffers-per-region= # Number of buffer per region.
server.undertow.direct-buffers= # Allocate buffers outside the Java heap.
server.undertow.io-threads= # Number of I/O threads to create for the worker.
server.undertow.max-http-post-size=0 # Maximum size in bytes of the HTTP post content.
server.undertow.worker-threads= # Number of worker threads.

到这里,肯定会有很多人有疑惑,非得用SpringBoot集成的容器作为运行环境吗?

SpringBoot同样提供了像往常一样打war包部署的解决方案。

1.将项目的启动类Application.java继承SpringBootServletInitializer并重写configure方法。

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }

}


2.在pom.xml文件中,< project >标签下面添加war包支持的< package >标签,或者将原标签值jar改成war。

 

<packaging>war</packaging>


3.在pom.xml文件中,去除tomcat依赖,或者将其标记为provided(打包时排除),provided方式有一点好处是调试是可以用内置tomcat。

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
</dependency>


至此,以上3个配置便可以完成war方式部署,注意war包部署后访问时需要加上项目名称
 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值