1. 程式人生 > >maven中使用tomcat7外掛servlet-api的jar包衝突

maven中使用tomcat7外掛servlet-api的jar包衝突

一、錯誤日誌

    tomcat容器啟動正常,訪問時報出如下錯誤:

配置如下:

maven的pom.xml配置

 

Java Build Path -->Libraries配置

原因分析:

        想必到這裡很多小夥伴已經明白了,但截圖都到這了,還是說一下,因為有些同學還是搞不清楚。你可能會遇到如下問題:pom.xml不新增servlet-api依賴,那麼專案直接就會報錯,因為你建立的是一個servlet的子類,編譯也無法通過,會報找不到類錯誤,英文我就不說了。但pom.xml中引入這個依賴,tomcat容器啟動沒問題,但你訪問的時候就出現了上面的錯誤。這就是jar包衝突了,那麼怎麼衝突的呢?首先,我們在pom.xml中引入了servlet-api這個依賴,但是我們使用了tomcat7外掛,我們看一下tomcat7外掛依賴哪些。根據tomcat7外掛的座標,我們找到在倉庫中的位置,看到有個檔案,

OK,我們開啟這個檔案,會發現,它依賴了

,我們繼續找,然後發現這個tomcat-servlet-api和我們自己在pom.xml引入的servlet-api有什麼區別呢,看下圖:

到這裡,發現jar包衝突了。我們編譯時使用的3.0的,執行期載入的也是3.0,但是載入這個類的類載入器許可權比較低,對於整個web容器裡的資源,載入的這個類可能訪問不到,導致出現這個問題。(注意,tomcat的類載入機制和JAVA預設的的不太一樣,它先載入WEB專案的)。

解決方式一:什麼都不用動,給我們自己引入的servlet-api加一個作用域

如果你不加,那麼這個依賴的作用域預設是<scope>compile</scope>,作用域什麼意思呢?如下:

compile:預設值,適用於所有階段(表明該jar包在編譯、執行以及測試中路徑俊可見),並且會隨著專案直接釋出。

provided:編譯和測試時有效,並且該jar包在執行時由伺服器提供。如servlet-api.

runtime:執行時使用,對測試和執行有效。如jdbc.

test:只在測試時使用,在編譯和執行時不起作用。釋出專案時沒有作用。

system:不依賴maven倉庫解析,需要提供依賴的顯式的置頂jar包路徑。對專案的移植來說是不方便的。

作用域變成provided後,我們編譯用的是我們自己引入的,而在執行時只能載入到tomcat容器的。

 

解決方式二:將我們自己引入的servlet-api去除,而是在Java Build Path -->Libraries配置中新增Server Runtim,如下:

這樣的目的是,編譯階段可以使用tomcat容器中的servlet-api了,執行時也是tomcat7容器中的servlet-api。

總結:

程式中使用到javax.servlet.http.HttpServletRequest等類內容,然而這些類是依賴於tomcat容器lib包下的jar包,工程中匯入這兩個jar包後就會和tomcat產生衝突。

javax包下都是jdk提供介面規範,由第三方伺服器廠商自己來實現。

工程中匯入的目的是為了能順利使用這兩個jar包,包含正確編譯、使用等。

 解決方式:

   1.在tomcat的context.xml中新增一段配置,這段配置的作用就是採用jvm的代理模式,優先使用父類包含的jar包。

  <Loader delegate="false"/>

        delegate值為true時,使用代理模式,載入前先訪問上級loader。 false代表從本web應用程式中查詢,不推薦。        

    2.如果使用maven,可以將依賴jar包的作用域調成provide,作用就是隻在編譯、測試環境下使用,釋出時jar包會由JDK或容器提供,不會發布此jar包。換言之,provide作用於不具有傳遞性。這也是與compile作用域的區別(compile會將jar釋出出去)。

    3.編寫專案以及釋出的時候將兩個jar複製到lib並加入buildpath,專案執行之前刪掉兩個jar。這種方式不方便,但是能達到效果。(不推薦)。

    4.無需複製jar包,直接將tomcat目錄下的jar新增到工程中。到build path中Add Library →User Library,將tomcat/lib下servlet-api.jar和jsp-api.jar放到User Library中,buildPath給工程就OK,Servelt Runtime的方式就比較粗暴。