最近某Java工程启动中抛出了一个诡异的问题, 堆栈比较长, 主要原因是:
java.lang.SecurityException: class "javax.servlet.AsyncListener"'s signer information does not match signer information of other classes in the same package
经Google, 发现是由于javax.servlet这个包中的众多类, 在多个Jar包中均有实现(比如X和Y都有实现), 如果该Java进程加载时, 使用了X.jar中的javax.servlet.A, 又加载了Y.jar中的javax.servlet.B, 同时X.jar和Y.jar的签名不一致, 这样会导致以上报错.
在IDE中查找类javax.servlet.AsyncListener
, 发现在多个带javaee或者servlet名字的jar包中均有实现, 可以通过以下命令获取工程的所有依赖:
mvn dependency:tree
为了定位是哪个Jar包导致的该问题, 我们在实现了这个类的Jar包中, 进行签名检查:
jarsigner -verify xxx.jar
通过这个命令可以看到该Jar是否有签名.
最后发现, 这些Jar包中, 只有一个有签名, 而其他都没有:
org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016:compile
所以可以推断应该是这个eclipse对servlet的实现的Jar包使用了签名, 导致和其他相关Jar包不兼容. (是有多喜欢造轮子)
而这个Jar包, 通过依赖树, 我们发现是hive-jdbc 2.3.2依赖引入的(看着hive依赖真混乱..., 记得hbase也是), 通过升级到 3.1.0, 再次检查依赖, 我们发现这个Jar包已经不在依赖树中了. 而启动错误也消失了.
或者还有另外一个方法, 把这个有问题的包从hive-jdbc 2.3.2 中exlucde掉, 让hive使用其他包中的javax.servlet
实现. 其实即便没有其他包有javax.servlet
的实现, 或者其scope为provided, 只要这个工程在tomcat中启动, 都是可以的. 因为tomcat自带servlet-api
实现.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。