记一次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就好了。

相关文章
相关标签/搜索