[英]Loading external classes that depend on internal classes
我正在嘗試為Java寫一個簡單的插件架構(它擴展了我們現有的某些功能,這就是為什么我沒有使用適當的插件庫的原因)
我在戰爭中有一個基類(使用JBoss部署):
package org.example.components;
public abstract class ComponentBase {
// Base code
}
我有一個jar custom-components.jar
其中包含一些自定義組件代碼:
package org.example.components.custom;
public class CustomComponent extends ComponentBase {
// Custom code
}
通過一些魔術,我的戰爭中的插件代碼獲得了CustomComponent
類的名稱並執行以下操作:
Class classToRegister = Class.forName("org.example.components.custom.CustomComponent");
但是,這引發了NoClassDefFoundError
,表示找不到org.example.components.ComponentBase
。
Caused by: java.lang.NoClassDefFoundError: org/example/components/ComponentBase
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at org.jboss.mx.loading.RepositoryClassLoader.findClassLocally(RepositoryClassLoader.java:690)
at org.jboss.mx.loading.RepositoryClassLoader.findClass(RepositoryClassLoader.java:670)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassLocally(RepositoryClassLoader.java:200)
at org.jboss.mx.loading.ClassLoadingTask$ThreadTask.run(ClassLoadingTask.java:131)
at org.jboss.mx.loading.LoadMgr3.nextTask(LoadMgr3.java:399)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:527)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:295)
at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:627)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1345)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1204)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
... 259 more
Caused by: java.lang.ClassNotFoundException: No ClassLoaders found for: org/example/components/ComponentBase
at org.jboss.mx.loading.LoadMgr3.beginLoadTask(LoadMgr3.java:212)
at org.jboss.mx.loading.RepositoryClassLoader.loadClassImpl(RepositoryClassLoader.java:521)
at org.jboss.mx.loading.RepositoryClassLoader.loadClass(RepositoryClassLoader.java:415)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
... 297 more
ComponentBase
已加載良好,因為我可以執行Class.forName('org.example.components.ComponentBase')
而不會出現錯誤。 初始化CustomComponent
時是否使用其他類加載器? 我嘗試顯式傳遞類加載器,但出現相同的錯誤。
由於您的插件基類位於WAR文件中(可能位於WEB-INF / classes / ...中),因此您需要從somewhere on the classpath
刪除custom-components.jar
並將其移至“ WEB-INF / lib”中您的war文件的文件夾。
這樣,兩個類都由同一個類加載器加載。
執行時現在擁有的方式:
Class.forName('org.example.components.ComponentBase')
它成功,因為您正在將ComponentBase加載到戰爭類加載器中。 forName方法首先檢查戰爭的WEB-INF / lib和WEB-INF / classs並找到它。
但是,當您執行
Class.forName("org.example.components.custom.CustomComponent");
戰爭類加載器首先像以前一樣檢查WEB-INF / lib,WEB-INF / class,但在那里找不到它。 然后,它開始詢問“父”類加載器。 父類加載器(可能是JBoss特定的類加載器,還是引導類加載器?)找到該類並嘗試加載它。
一切正常,直到它檢測到CustomComponent擴展了BaseComponent。 因此,父類加載器嘗試加載BaseComponent。 但是,父類加載器找不到BaseComponent,因為不允許在war文件中查找它。 您戰爭類加載器是子類加載器,並且類加載器只能委托給父類加載器。
考慮一下如果您取消部署戰爭而您的基礎階級走了會發生什么。 或者,如果您部署了兩次戰爭,都與您的基類一起進行。 在啟動類路徑上依賴於可能消失或成倍增加的基類的插件類的想法是沒有意義的。
現在,只需將所有代碼放在WAR文件中,並使類加載邏輯盡可能簡單即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.