解決Java執行過程中拋簽名異常的問題

EthanSun發表於2019-01-19

最近某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實現.

相關文章