springboot:修改內置tomcat版本

背景

在 spring boot 出來以前,或者沒有使用 spring boot 時,Java EE 開發時若是選擇 tomcat servlet,須要本身指定 tomcat 版本;此處沒有考慮那種直接把打包的 war 直接扔到本地安裝的任意版本的 tomcat,而後啓動外置 tomcat 的狀況。java

使用 spring boot (內置 tomcat)時,通常狀況下,徹底沒有必要去修改 tomcat 的版本,就算是生產環境使用的 spring boot 內置版本,也是最好使用 spring boot 的內置的 tomcat 版本,這是通過兼容測試、迴歸測試的版本號。web

可是,不少公司都不推薦各個應用使用內置 tomcat 這種方式,由於這樣的話,100 個服務,可能有幾十種版本的 tomcat,不方便統一管理,太老的 tomcat 版本有問題,太新的版本不穩定。因此不少公司仍然在使用通過不少公司多年生產環境校驗的 tomcat 7,甚至是 tomcat 6。隨着版本的提高,依賴於 tomcat 的良好架構設計,其後續版本的各類性能提高,對於 http 2的支持,難道你真的捨得不去嘗試使用嗎?spring

不過,本地開發時,徹底能夠隨意使用最新版本的 tomcat,若是是使用 spring boot,而且是使用內置 tomcat 的話,直接使用最新版本的 sb 便可,由於每次 sb 升級,都會升級 tomcat 版本。可是最新版本 sb 可能有不兼容等問題,有些人可能不會去嘗試使用。apache

若是不是使用 spring boot 內置 tomcat,而是想使用任意版本的 tomcat 呢?tomcat

下來詳細講講怎麼修改 tomcat 的版本吧,也是去試着理解一下 tomcat 的啓動過程,以及 spring boot 如何內嵌集成 tomcat 的。
想要修改內置的 tomcat 的默認版本,首先得知道當前是什麼版本。websocket

如何知道當前使用的版本

方法1:藉助於IDEA

好比我當前的 sb 版本是:架構

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
</parent>

藉助於 IDE,查看 spring-boot-starter-tomcat 的 pom 文件:eclipse

<dependencies>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-core</artifactId>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-el</artifactId>
	</dependency>
	<dependency>
		<groupId>org.apache.tomcat.embed</groupId>
		<artifactId>tomcat-embed-websocket</artifactId>
	</dependency>
</dependencies>

可知全部的 jar。
此時若是是 eclipse 的忠實用戶,則能夠在當前工程 project 的 maven 依賴裏面直接去看 jar 的版本號。socket

IDEA 則略有不一樣,IDEA 的 module 概念等於 eclipse 的 project 概念。IDEA 在 External Libraries下面並不能看到版本號信息,尤爲是對於多個 module 的工程 project 而言,不一樣 module 使用不一樣的 tomcat 版本時如何知道當前 module 使用的是什麼版本的 tomcat 呢?
External Libraries
實際上,此時就是要去理解 IDEA 的設計意圖咯,我認爲 External Libraries 的做用主要是去看源碼和用於debug。在右側還有一個面板 Maven Projects,找到當前 module,打開 dependencies 信息,而後此時還能夠查看 jar 包,即 artifactId 的依賴管理關係:
這裏寫圖片描述
可知 spring boot 1.5.7 的內置 tomcat 版本是 8.5.20。maven

方法2:沒有IDE, 怎麼知道版本信息?

打開本地maven repository目錄下的spring-boot-dependencies文件:
/Users/awesome-me/.m2/repository/org/springframework/boot/spring-boot-dependencies/1.5.7.RELEASE/spring-boot-dependencies-1.5.7.RELEASE.pom
能夠在標籤<properties>下面找到<tomcat.version>8.5.20</tomcat.version>

修改內置的默認版本

從上面的方法2,就知道如何修改的思路。
即在 pom.xml 文件裏面添加一個標籤<properties>,添加指望的版本<tomcat.version>8.0.30</tomcat.version>
如何知道修改是否成功?
修改爲<tomcat.version>8.0.30</tomcat.version>
啓動信息:

2018-03-15 00:46:26.275  INFO 47112 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-03-15 00:46:26.282  INFO 47112 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2018-03-15 00:46:26.283  INFO 47112 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.30
2018-03-15 00:46:26.333  INFO 47112 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-15 00:46:26.333  INFO 47112 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1000 ms

可是,有時候啓動會報錯:

Caused by: java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory 
  at org.apache.catalina.util.LifecycleBase.<clinit>(LifecycleBase.java:37) 
  at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:169) 
  at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:164) 
  at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:134) 
  ... 13 common frames omitted

顯然是缺乏 jar 包,在 dependency 裏面添加如下二者之一便可:

<dependency> 
   <groupId>org.apache.tomcat</groupId> 
   <artifactId>tomcat-juli</artifactId> 
   <version>${tomcat.version}</version> 
 </dependency>

若是項目是使用內嵌Tomcat servlet容器形式打包部署,推薦使用下面這個,其groupId和artifactId皆是embed類型的jar包。若是項目是以war包形式打包部署,即pom標籤是war,則推薦使用上面這個。

<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-logging-juli</artifactId>
    <version>${tomcat.version}</version>
</dependency>

可是,還有一個問題:
spring-boot-starter-web是包含spring-boot-starter-tomcat的,查看 pom 文件可知。
也就是說,咱們沒有必要重複添加spring-boot-starter-tomcat,一個spring-boot-starter-web就能夠把一個典型的 spring web 項目搭建成功,也方便 jar 包的管理,此時須要額外添加Tomcat的GA:

<properties>
	<tomcat.version>8.0.30</tomcat.version>
</properties>
<!-- 顯式指定Tomcat版本 -->
<dependency>
   <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>${tomcat.version}</version>
</dependency>