java - 如何在運作時加載jar檔案
這個問題在這裡已有答案:
我應該如何在運作時動态加載Jars? 15個答案
我被要求建構一個能夠在運作時加載新代碼(擴充)的java系統。在代碼運作時如何重新加載jar檔案? 或者我如何裝一個新的罐子?
顯然,由于恒定的正常運作時間很重要,我想添加在其中重新加載現有類的能力(如果它不會使事情複雜化太多)。
我應該注意什麼?(把它想象成兩個不同的問題 - 一個關于在運作時重新加載類,另一個關于添加新類)。
5個解決方案
79 votes
使用現有資料重新加載現有類可能會破壞事物。
您可以相對輕松地将新代碼加載到新的類加載器中:
ClassLoader loader = URLClassLoader.newInstance(
new URL[] { yourURL },
getClass().getClassLoader()
);
Class> clazz = Class.forName("mypackage.MyClass", true, loader);
Class extends Runnable> runClass = clazz.asSubclass(Runnable.class);
// Avoid Class.newInstance, for it is evil.
Constructor extends Runnable> ctor = runClass.getConstructor();
Runnable doRun = ctor.newInstance();
doRun.run();
不再使用的類加載器可以被垃圾收集(除非存在記憶體洩漏,通常使用ThreadLocal,JDBC驅動程式,URLClassLoader.addURL等)。
如果你想保留對象資料,那麼我建議一個持久性機制,比如序列化,或者你習慣的任何東西。
當然,調試系統可以做更好的事情,但更麻煩,更不可靠。
可以将新類添加到類加載器中。 例如,使用URLClassLoader.addURL.但是,如果一個類無法加載(因為,例如,您還沒有添加它),那麼它将永遠不會加載到該類加載器執行個體中。
Tom Hawtin - tackline answered 2019-05-26T13:00:45Z
34 votes
這對我有用:
File file = new File("c:\\myjar.jar");
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("com.mypackage.myclass");
Yannick Rot answered 2019-05-26T13:01:04Z
8 votes
我被要求建構一個能夠在運作時加載新代碼的java系統
您可能希望将系統基于OSGi(或者至少需要花費很多時間),這正是針對這種情況而制定的。
與類加載器混淆是非常棘手的業務,主要是因為類可見性如何工作,并且您不希望以後遇到難以調試的問題。 例如,在許多庫中廣泛使用的Class.forName()在碎片類加載器空間上不能很好地工作。
Thilo answered 2019-05-26T13:01:44Z
3 votes
我google了一下,在這裡找到了這段代碼:
File file = getJarFileToLoadFrom();
String lcStr = getNameOfClassToLoad();
URL jarfile = new URL("jar", "","file:" + file.getAbsolutePath()+"!/");
URLClassLoader cl = URLClassLoader.newInstance(new URL[] {jarfile });
Class loadedClass = cl.loadClass(lcStr);
任何人都可以就這種方法分享意見/評論/答案嗎?
Amir Arad answered 2019-05-26T13:02:15Z
2 votes
使用org.openide.util.Lookup和ClassLoader動态加載Jar插件,如下所示。
public LoadEngine() {
Lookup ocrengineLookup;
Collection ocrengines;
Template ocrengineTemplate;
Result ocrengineResults;
try {
//ocrengineLookup = Lookup.getDefault(); this only load OCREngine in classpath of application
ocrengineLookup = Lookups.metaInfServices(getClassLoaderForExtraModule());//this load the OCREngine in the extra module as well
ocrengineTemplate = new Template(OCREngine.class);
ocrengineResults = ocrengineLookup.lookup(ocrengineTemplate);
ocrengines = ocrengineResults.allInstances();//all OCREngines must implement the defined interface in OCREngine. Reference to guideline of implement org.openide.util.Lookup for more information
} catch (Exception ex) {
}
}
public ClassLoader getClassLoaderForExtraModule() throws IOException {
List urls = new ArrayList(5);
//foreach( filepath: external file *.JAR) with each external file *.JAR, do as follows
File jar = new File(filepath);
JarFile jf = new JarFile(jar);
urls.add(jar.toURI().toURL());
Manifest mf = jf.getManifest(); // If the jar has a class-path in it's manifest add it's entries
if (mf
!= null) {
String cp =
mf.getMainAttributes().getValue("class-path");
if (cp
!= null) {
for (String cpe : cp.split("\\s+")) {
File lib =
new File(jar.getParentFile(), cpe);
urls.add(lib.toURI().toURL());
}
}
}
ClassLoader cl = ClassLoader.getSystemClassLoader();
if (urls.size() > 0) {
cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), ClassLoader.getSystemClassLoader());
}
return cl;
}
Doan Huynh answered 2019-05-26T13:02:40Z