我有一個Web服務,我們將其稱爲service.war。它實現了一個我們稱之爲ServicePluginInterface的接口。在啓動service.war期間,它會讀取環境變量並使用它們來搜索jar(MyPlugin.jar)。當它找到jar時,它會使用第二個環境變量在jar中加載插件。它加載的類看起來是這樣的:如何實現從WAR中提取的共享接口
public class MyPlugin implements ServicePluginInterface {...}
該servlet嘗試使用如下代碼加載插件:
try {
if (pluginClass == null) {
plugin = null;
}
else {
ZipClassLoader zipLoader = new ZipClassLoader(Main.class.getClassLoader(), pluginJar);
plugin = (ServicePluginInterface)zipLoader.loadClass(pluginClass).newInstance();
plugin.getAccount(null,null);
}
} catch (Exception e) {
...
}
訣竅是,我沒有源或ServicePluginInterface罐子。不想放棄這麼容易,我把class文件從service.war文件中提取出來。通過使用這些類文件作爲依賴項,我能夠在沒有編譯器警告的情況下構建MyPlugin。然而,當實際的Tomcat執行時,代碼的部分上方產生一個運行時異常:
java.lang.ClassCastException: com.whatever.MyPlugin cannot be cast to com.whomever.ServicePluginInterface
作爲參考的第二點,我還能夠構建合成的類加載器(單獨的Java可執行同樣,由於我沒有ServicePluginInterface的原始源代碼,所以我使用了WAR中的類文件,第二個是合成加載器,或者假的servlet,如果你願意,可以加載MyPlugin。我會假設Tomcat JVM似乎正在檢測WAR中發現的類與提取的類文件之間的某種區別,然而,因爲我所做的所有提取類文件都是以WAR作爲zip打開,把它們複製出來,很難想象它會是什麼。
哈維爾提出了有益的建議有關刪除ServicePluginInterface的定義,該解決方案的問題是,ZipClassLoader該servlet使用加載插件出來的罐子將覆蓋類加載器的findClass功能拉班出來該JAR像這樣的:
protected Class<?> findClass(String name) throws ClassNotFoundException
{
ZipEntry entry = this.myFile.getEntry(name.replace('.', '/') + ".class");
if (entry == null) {
throw new ClassNotFoundException(name);
}
...
}
類ZipClassLoader然後遞歸加載所有的父對象和接口從罐子。這意味着如果插件jar不包含ServicePluginInterface的定義,它將會失敗。由不同類加載器所定義
爲什麼ZipClassLoader不能委託給它的父項?它是什麼實現? – Javier
不幸的是,我認爲ZipClassLoader對servlet所有者有版權,所以我不能完全分享它,但現在我想知道是否可以編寫更好的ZipClassLoader並在WAR中替換類文件。 .. – OverclockedTim