[原创] 解决错误“class "javax.servlet.FilterRegistration"'s signer information does not match signer information of other classes in the same package”

这是一个jar包冲突引起的Java程序错误,而且是runtime的错误,编译的时候不出错,一运行起来就挂。

大致的错误信息如下:

Thread[main,5,main] exit with uncaught error java.lang.SecurityException: class "javax.servlet.FilterRegistration"'s signer information does not match signer information of other classes in the same package
java.lang.SecurityException: class "javax.servlet.FilterRegistration"'s signer information does not match signer information of other classes in the same package
        at java.lang.ClassLoader.checkCerts(ClassLoader.java:895)
        at java.lang.ClassLoader.preDefineClass(ClassLoader.java:665)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:758)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

网上一搜就知道,这是jar包冲突引起的,也就是说,classpath中的两个版本不同的jar包都含有FilterRegistration类的实现,并且它们不兼容。
文章来源:http://www.codelast.com/
在IntelliJ IDEA中使用“Go to class”功能(快捷键Ctrl+N),在里面输入“FilterRegistration”,可以快速定位到这个类,从而得知它所在的jar包是javax.servlet-api-3.0.1.jar(你的项目可能版本不同,但这并不妨碍我们分析),也就是在pom.xml中引入的:

  1. <dependency>     
  2.   <groupId>javax.servlet</groupId>      
  3.   <artifactId>javax.servlet-api</artifactId>     
  4. </dependency>

那为什么会产生冲突呢?虽然你的pom.xml文件(Maven的工程)里只包含有一个javax-servlet-api的依赖,但是有其他的jar包会间接依赖于其他版本的 servlet-api,从而可能会产生冲突。
为了找出这个冲突的jar包,你可以使用IntelliJ IDEA的Maven插件Maven Helper来帮忙,或者你不愿装新插件的话,直接用如下命令来导出各jar包的依赖关系:

mvn dependency:tree > x.txt

在这里,我把结果输出到了一个文件 x.txt 中,内容类似于(仅部分):

[INFO] +- org.apache.httpcomponents:httpclient:jar:4.2.3:compile
[INFO] +- org.apache.httpcomponents:httpcore:jar:4.2.1:compile
[INFO] +- org.eclipse.jetty.aggregate:jetty-all-server:jar:8.1.15.v20140411:compile
[INFO] |  +- org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016:compile
[INFO] |  +- org.eclipse.jetty.orbit:javax.security.auth.message:jar:1.0.0.v201108011116:compile
[INFO] |  +- org.eclipse.jetty.orbit:javax.mail.glassfish:jar:1.4.1.v201005082020:compile
[INFO] |  +- org.eclipse.jetty.orbit:javax.activation:jar:1.1.0.v201105071233:compile
[INFO] |  \- org.eclipse.jetty.orbit:javax.annotation:jar:1.1.0.v201108011116:compile
[INFO] +- com.jcraft:jsch:jar:0.1.44:compile

可见,间接依赖的jar包被列出来了。在输出的文件中查找“sevlet-api”,会找到好几个间接依赖了servlet-api的jar包,而它们正是不同于3.0.1的版本(我前面主动引入的是3.0.1的版本,间接引入的不是),例如hadoop-common就是一个“幕后黑手”,它依赖了 2.5 的servlet-api。
文章来源:http://www.codelast.com/
于是我们需要在pom.xml中,视情况把不同版本的servlet-api给“除掉”,这里我选择的是除掉hadoop-common中的旧版本servlet-api:

  1. <dependency>  
  2. <groupId>org.apache.hadoop</groupId>  
  3. <artifactId>hadoop-common</artifactId>  
  4. <exclusions>  
  5. <exclusion>  
  6.   <groupId>javax.servlet</groupId>  
  7.   <artifactId>*</artifactId>  
  8. </exclusion>  
  9. </exclusions>  
  10. </dependency>

依次检查完所有的间接依赖,一个个处理好,再重新编译程序,测试,直到程序可以正常跑起来。
这里需要特别注意,如果程序运行前export的CLASSPATH中的某个路径里有旧的jar包,一定要清理干净再测试,否则可能你已经在pom.xml中解决了问题,但无论怎么测都不行,仍然还是jar包冲突,结果发现是CLASSPATH中的某个路径下的旧jar包没清理干净导致的,那就浪费时间了。

文章来源:https://www.codelast.com/
➤➤ 版权声明 ➤➤ 
转载需注明出处:codelast.com 
感谢关注我的微信公众号(微信扫一扫):

wechat qrcode of codelast

发表评论