如何在运行时加载一个jar文件
我被要求构建一个Java系统,在运行时可以加载新的代码(扩展)。 如何在代码运行时重新加载jar文件? 或者我如何加载一个新的jar?
很明显,由于持续运行时间很重要,所以我想增加重新加载现有类的能力(如果它不太复杂)。
我应该注意些什么? (把它想成两个不同的问题 – 一个是在运行时重新加载类,另一个是关于添加新类的问题)。
用现有数据重新加载现有的类可能会破坏事物。
您可以相对容易地将新代码加载到新的类加载器中:
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驱动程序, java.beans
等常常是这种情况)。
如果你想保留对象数据,那么我建议一个持久化机制,比如Serialization,或者你习惯的任何东西。
当然,调试系统可以做更有趣的事情,但更可笑,更不可靠。
可以将新类添加到类加载器中。 例如,使用URLClassLoader.addURL
。 但是,如果一个类加载失败(因为你没有添加它),那么它将永远不会加载该类加载器实例。
这适用于我:
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");
我被要求构建一个能够在运行时加载新代码的Java系统
您可能希望将您的系统建立在OSGi上 (或者至少花费很多),这正是为了这种情况而做出的。
对于类加载器来说是一件非常棘手的事情,主要是因为类的可见性是如何工作的,而且以后不想遇到难以调试的问题。 例如,在许多库中广泛使用的Class.forName()在片段化类加载器空间上效果不佳。
我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);
任何人都可以分享有关这种方法的意见/评论/答案?
使用org.openide.util.Lookup和ClassLoader动态加载Jar插件,如下所示。
public LoadEngine() { Lookup ocrengineLookup; Collection<OCREngine> 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<URL> urls = new ArrayList<URL>(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; }