天天看點

java 加載 jar_java - 如何在運作時加載jar檔案

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