<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          什么?編譯了三個(gè)版本Tomcat源碼后,我才發(fā)現(xiàn)這個(gè)bug

          共 5435字,需瀏覽 11分鐘

           ·

          2021-03-22 15:06

          走過(guò)路過(guò)不要錯(cuò)過(guò)

          點(diǎn)擊藍(lán)字關(guān)注我們


          背景

          一產(chǎn)品是基于多模塊開(kāi)發(fā)的 SpringBoot 項(xiàng)目,發(fā)布時(shí)導(dǎo)出多個(gè) war 包部署在同一個(gè) Tomcat 。模塊有五六個(gè),發(fā)布時(shí)最大的問(wèn)題就是每個(gè)包都很大,主要是各個(gè)模塊的 WEB-INF/lib 下包含大量相同 jar ,因此有必要將公共包摘出來(lái)放到 Tomcat 的共享目錄下。

          然而,在搗鼓了兩天后,我對(duì) Tomcat 的多應(yīng)用部署時(shí)共享公共包的能力產(chǎn)生了懷疑。理論上,同一個(gè) Tomcat 下部署多個(gè)應(yīng)用時(shí),可以將所有共享 jar 放在 shared/lib 目錄下,然后配置 shared.loader 就可以了。

          實(shí)踐的時(shí)候,抽取了公共包后,多個(gè) war 部署時(shí)始終報(bào)錯(cuò), WEB-INF/lib 下明明有對(duì)應(yīng)的 Spring 框架包,還是報(bào) Caused by: 
          java.lang.NoClassDefFoundError: org/springframework/beans/factory/FactoryBean 異常,反復(fù)測(cè)試,還是無(wú)法確定哪些包應(yīng)該作為公共包。

          所以,決定從源頭來(lái)搞明白這個(gè)類(lèi)加載過(guò)程,在編譯的 Tomcat 版本下斷點(diǎn)跟蹤一下到底是怎么回事兒。第一件事兒,先編譯 Tomcat 源碼。

          Tomcat 源碼編譯

          Tomcat 源碼導(dǎo)入 IDEA 的過(guò)程比較簡(jiǎn)單,步驟為:

          1.下載 ANT 工具,最新版本為 1.10.9,配置環(huán)境變量 ANT_HOME:

          2.下載 tomcat 源碼,根據(jù)操作系統(tǒng)選擇 zip 或者 tar.gz 文件;

          3.進(jìn)入源碼目錄,使用 ant 命令編譯源碼;

          此操作耗時(shí)較長(zhǎng),耐心等待編譯完成:

          4. 創(chuàng)建一個(gè) catalina-home 目錄,將 output/build 目錄下的所有文件拷貝到 catalina-home 目錄下,將其作為 Tomcat 的工作目錄:

          5.進(jìn)入源碼目錄,創(chuàng)建 pom.xml 添加依賴(lài):

          <?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>
          <groupId>org.apache.tomcat</groupId>
          <artifactId>Tomcat8.0</artifactId>
          <name>Tomcat8.0</name>
          <version>8.0</version>

          <build>
          <finalName>Tomcat8.0</finalName>
          <sourceDirectory>java</sourceDirectory>
          <!--<testSourceDirectory>test</testSourceDirectory>-->
          <resources>
          <resource>
          <directory>java</directory>
          </resource>
          </resources>
          <!--<testResources>-->
          <!--<testResource>-->
          <!--<directory>test</directory>-->
          <!--</testResource>-->
          <!--</testResources>-->
          <plugins>
          <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
          <configuration>
          <encoding>UTF-8</encoding>
          <source>1.7</source>
          <target>1.7</target>
          </configuration>
          </plugin>
          </plugins>
          </build>

          <dependencies>
          <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
          </dependency>
          <dependency>
          <groupId>org.easymock</groupId>
          <artifactId>easymock</artifactId>
          <version>3.4</version>
          </dependency>
          <dependency>
          <groupId>ant</groupId>
          <artifactId>ant</artifactId>
          <version>1.7.0</version>
          </dependency>
          <dependency>
          <groupId>wsdl4j</groupId>
          <artifactId>wsdl4j</artifactId>
          <version>1.6.2</version>
          </dependency>
          <dependency>
          <groupId>javax.xml</groupId>
          <artifactId>jaxrpc</artifactId>
          <version>1.1</version>
          </dependency>
          <dependency>
          <groupId>org.eclipse.jdt.core.compiler</groupId>
          <artifactId>ecj</artifactId>
          <version>4.5.1</version>
          </dependency>
          </dependencies>
          </project>

          6.導(dǎo)入 IDEA 源碼,配置啟動(dòng)參數(shù) -Dcatalina.home="F:\Study\TomcateStudy\2021Tomcat\catalina-home" 。

          總的來(lái)說(shuō),編譯源碼流程比較簡(jiǎn)單,但最開(kāi)始因?yàn)殡S便選擇了最新版本,導(dǎo)致無(wú)法啟動(dòng),這可能是官網(wǎng)版本發(fā)布時(shí)的缺陷吧,反正換個(gè)版本就沒(méi)有問(wèn)題。

          選錯(cuò)版本的問(wèn)題

          首先,在 MAC 操作系統(tǒng)下,隨便選擇了最新版本 tomcat8.5.63 的 tar.gz 版本,下載后,編譯時(shí)報(bào)錯(cuò)。先報(bào) @Version@ 校驗(yàn)錯(cuò)誤:

          Error:osgi: [Tomcat8.5] Invalid value for Bundle-Version, @VERSION@ does not

          修改為一個(gè)特定值后,又報(bào)下面的錯(cuò)誤:

          最初懷疑是 IDEA 配置問(wèn)題,于是又在 windows 操作系統(tǒng)下,還是用最新版本的 tomcat8.5.63 的 zip 版本下載源碼,配置參數(shù)如下:

          奇怪的是,它能夠編譯通過(guò)、正常運(yùn)行:

          結(jié)論:Tomcat8.5.63 版本的 tar.gz 源碼的 jdbc-pool 模塊打包生成的 MANIFEST.MF 文件有問(wèn)題,編譯源碼的時(shí)候應(yīng)該避免使用該版本。本來(lái)以為哪個(gè)版本都一樣,就隨便選了最新版本,結(jié)果就踩坑了。

          最后,更換為 Tomcat8.5.59 版本,MAC 下就能正確啟動(dòng)了。

          控制臺(tái)亂碼問(wèn)題

          最后解決控制臺(tái)亂碼問(wèn)題,主要涉及到兩個(gè)類(lèi),它們使用了默認(rèn)編碼導(dǎo)致輸出亂碼的。具體操作如下,詳細(xì)參考:

          第一步,修改 
          org.apache.tomcat.util.res.StringManager 類(lèi)的 getString(final String key, final Object... args) 方法,獲得 value 后再轉(zhuǎn)碼:

          try{
          value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
          }catch (Exception e ){
          e.printStackTrace();
          }

          第二步,修改 
          org.apache.jasper.compiler.Localizer 類(lèi)的 getMessage(String errCode) 方法,在返回之前進(jìn)行轉(zhuǎn)碼:

           try{
          errMsg = new String(errMsg.getBytes("ISO-8859-1"),"UTF-8");
          }catch (Exception e ){
          e.printStackTrace();
          }

          再重啟 Tomcat 應(yīng)用,輸出信息就正常了:

          啟示錄

          到現(xiàn)在為止,還沒(méi)找到答案的幾個(gè)問(wèn)題是:

          1. 多應(yīng)用共享 lib 的原則是什么?

          2. 哪些包應(yīng)該放在 shared/lib 下?【我是將純第三方 jar ,無(wú)相關(guān)依賴(lài)的】

          3. 為什么只 WEB-INF/lib 下只保留某個(gè)應(yīng)用自身的 jar 而且包含 SpringBoot 的 starter 依賴(lài),還是報(bào)類(lèi)異常?



          往期精彩推薦



          騰訊、阿里、滴滴后臺(tái)面試題匯總總結(jié) — (含答案)

          面試:史上最全多線程面試題 !

          最新阿里內(nèi)推Java后端面試題

          JVM難學(xué)?那是因?yàn)槟銢](méi)認(rèn)真看完這篇文章


          END


          關(guān)注作者微信公眾號(hào) —《JAVA爛豬皮》


          了解更多java后端架構(gòu)知識(shí)以及最新面試寶典


          你點(diǎn)的每個(gè)好看,我都認(rèn)真當(dāng)成了


          看完本文記得給作者點(diǎn)贊+在看哦~~~大家的支持,是作者源源不斷出文的動(dòng)力


          作者:畢小寶
          鏈接:https://juejin.cn/post/6925741351971586055
          來(lái)源:掘金

          瀏覽 95
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草成人在线观看 | 91福利视频在线观看 | 91精品国产综合久久久不卡电影 | 亚洲天天| 大香蕉最新视频网站 |