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 |
|
1.2設置Spring Boot主要應用程序和控制器
要設置Spring Boot應用程序,您可以在Main類中包含@SpringBootApplication批註。 @SpringBootApplication批註引入了@ SpringBootConfiguration,@ EnableAutoConfiguration和@ComponentScan批註。
Application.java
1 2 3 4 5 6 |
|
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 |
|
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 |
|
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 |
|
pom.xml
1 2 3 4 |
|
1 |
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 |
|
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 |
|
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 |
|
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 |
|
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容器。 由於應用程序要求(包括性能,內存使用情況和功能),許多默認設置將不得不更改。
更換內置容器,能提高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包部署後訪問時需要加上項目名稱