記一次jar包衝突致使項目啓動失敗的處理過程【java.lang.NoSuchMethodError:javax.servlet.ServletContext】

自從搞明白idea下,Jetty採用main方法啓動web項目後,準備大刀闊斧地把其餘web項目也改爲jetty啓動,不幸的是,第一個項目就遇到了問題,這裏記錄下整個排查流程及處理辦法。java

1. 異常發生

項目按idea下,Jetty採用main方法啓動web項目一文中所述的進行配置後,運行,發現出現了以下異常:web

java.lang.NoSuchMethodError: javax.servlet.ServletContext.getJspConfigDescriptor()Ljavax/servlet/descriptor/JspConfigDescriptor;
	at org.apache.jasper.servlet.TldScanner.scanJspConfig(TldScanner.java:158)
	at org.apache.jasper.servlet.TldScanner.scan(TldScanner.java:104)
	at org.apache.jasper.servlet.JasperInitializer.onStartup(JasperInitializer.java:103)
	......

在idea中一查javax.servlet.ServletContext,發現共有4個jar包中有這個類,分別是:apache

  • javax.servlet-api-3.0.1.jar
  • tomcat-embed-core-9.0.13.jar
  • javax.servlet-api-3.1.0.jar
  • servlet-api-2.4.jar

爲何會有這麼多servlet-api的版本呢?主要是由於在當前的項目中,還有其餘web模塊,因爲版本控制沒作好,每一個web模塊使用了不一樣的servlet-api,此外,還有一些jar包在引入時,一不當心就連帶引入了servlet-api的jar包。api

因此當務之急,就是找到該web模塊中的javax.servlet.ServletContext究竟來自於哪一個jar包。tomcat

2. 查看類引入路徑

爲了找到項目中類的加載狀況,須要在jvm的啓動參數中,添加-verbose:classapp

3. 啓動,查看控制檯日誌

再次啓動,能夠看到控制檯已經打出了類加載信息了,包括類名、jar包位置:eclipse

[Opened C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Object from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.io.Serializable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Comparable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.CharSequence from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.String from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.AnnotatedElement from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.GenericDeclaration from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.reflect.Type from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Class from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Cloneable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.ClassLoader from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.System from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
[Loaded java.lang.Throwable from C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar]
......

異常中出現問題的類是javax.servlet.ServletContext,在日誌搜索,發現以下記錄:webapp

[Loaded javax.servlet.ServletContext from file:/C:/Users/Administrator/.m2/repository/javax/servlet/servlet-api/2.4/servlet-api-2.4.jar]

能夠看到,項目中,javax.servlet.ServletContext類是由servlet-api-2.4.jar包引入的。jvm

關於「如何在控制檯中搜索」,能夠將控制檯日誌複製一份到文本編輯器中,如notepad++vscode等,而後使用搜索功能。jsp

4. 使用maven定位jar包來源

目前已經知道,項目中的javax.servlet.ServletContext類是由servlet-api-2.4.jar包引入的,但servlet-api-2.4.jar是從哪裏引入的呢?項目jar包是由maven來管理的,所以使用mvn命令來查找jar包引入狀況,命令以下:

mvn dependency:tree -Dverbose -Dincludes=*:*servlet*

運行以後,控制檯輸出以下:

[INFO] com.test:test-web:war:0.0.1-SNAPSHOT
[INFO] +- javax.servlet:servlet-api:jar:2.4:provided
[INFO] +- org.eclipse.jetty:jetty-webapp:jar:9.3.2.v20150730:test
[INFO] |  \- org.eclipse.jetty:jetty-servlet:jar:9.3.2.v20150730:test
[INFO] \- org.eclipse.jetty:apache-jsp:jar:9.3.2.v20150730:test
[INFO]    +- org.eclipse.jetty:jetty-server:jar:9.3.2.v20150730:test
[INFO]    |  \- (javax.servlet:javax.servlet-api:jar:3.1.0:test - omitted for duplicate)
[INFO]    \- javax.servlet:javax.servlet-api:jar:3.1.0:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

能夠看到,項目中引入的servlet-api版本是2.4,而jetty使用的servlet-api版本是3.1.0,這樣就致使了jetty中使用了低版本的servlet-api,從而出現異常。

明白了問題所在,解決就很簡單了,只要將項目servlet-api的版本由2.4升級到3.1.0就好了。

相關文章
相關標籤/搜索