背景
在 spring boot 出來之前,或者沒有使用 spring boot 時,Java EE 開發時如果選擇 tomcat servlet,需要自己指定 tomcat 版本;此處沒有考慮那種直接把打包的 war 直接扔到本地安裝的任意版本的 tomcat,然后啟動外置 tomcat 的情況。
使用 spring boot (內置 tomcat)時,一般情況下,完全沒有必要去修改 tomcat 的版本,就算是生產環境使用的 spring boot 內置版本,也是最好使用 spring boot 的內置的 tomcat 版本,這是經過兼容測試、回歸測試的版本號。
但是,很多公司都不推薦各個應用使用內置 tomcat 這種方式,因為這樣的話,100 個服務,可能有幾十種版本的 tomcat,不方便統一管理,太老的 tomcat 版本有問題,太新的版本不穩定。所以很多公司仍然在使用經過很多公司多年生產環境校驗的 tomcat 7,甚至是 tomcat 6。隨着版本的提升,依賴於 tomcat 的良好架構設計,其后續版本的各種性能提升,對於 http 2的支持,難道你真的舍得不去嘗試使用嗎?
不過,本地開發時,完全可以隨意使用最新版本的 tomcat,如果是使用 spring boot,並且是使用內置 tomcat 的話,直接使用最新版本的 sb 即可,因為每次 sb 升級,都會升級 tomcat 版本。但是最新版本 sb 可能有不兼容等問題,有些人可能不會去嘗試使用。
如果不是使用 spring boot 內置 tomcat,而是想使用任意版本的 tomcat 呢?
下來詳細講講怎么修改 tomcat 的版本吧,也是去試着理解一下 tomcat 的啟動過程,以及 spring boot 如何內嵌集成 tomcat 的。
想要修改內置的 tomcat 的默認版本,首先得知道當前是什么版本。
如何知道當前使用的版本
方法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 文件:
<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 的版本號。
IDEA 則略有不同,IDEA 的 module 概念等於 eclipse 的 project 概念。IDEA 在 External Libraries下面並不能看到版本號信息,尤其是對於多個 module 的工程 project 而言,不同 module 使用不同的 tomcat 版本時如何知道當前 module 使用的是什么版本的 tomcat 呢?
實際上,此時就是要去理解 IDEA 的設計意圖咯,我認為 External Libraries 的作用主要是去看源碼,debug。在右側還有一個面板 Maven Projects,找到當前 module,打開 dependencies 信息,然后此時還可以查看 jar 包,即 artifactId 的依賴管理關系:
可知 spring boot 1.5.7 的內置 tomcat 版本是 8.5.20。
方法2:沒有IDE, 怎么知道版本信息?
打開文件:
/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>
但是還有另外一個 artifactId
<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 包的管理。
但是,如果此時你的項目中僅僅添加spring-boot-starter- web
,而沒有直接添加spring-boot-starter-tomcat
,就算配置
<properties> <tomcat.version>9.0.6</tomcat.version> <!--<tomcat.version>8.0.30</tomcat.version>--> </properties>
也並不能生效。至於為什么,有待研究 spring boot 的 autoconfigure 源碼才能知道吧。