首页 文章

如何在运行时加载jar文件[重复]

提问于
浏览
72

这个问题在这里已有答案:

我被要求构建一个能够在运行时加载新代码(扩展)的java系统 . 我的代码运行时如何重新加载jar文件?或者我如何装一个新的 jar ?

显然,由于恒定的正常运行时间非常重要,我想添加在现有类重新加载的能力(如果它不会使事情复杂化太多) .

我应该注意什么? (把它想象成两个不同的问题 - 一个关于在运行时重新加载类,另一个关于添加新类) .

5 回答

  • 3

    使用现有数据重新加载现有类可能会破坏事物 .

    您可以相对轻松地将新代码加载到新的类加载器中:

    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 等) .

    如果你想保留对象数据,那么我建议一个持久性机制,如序列化,或者你习惯的任何东西 .

    当然,调试系统可以做更好的事情,但更麻烦,更不可靠 .

    可以将新类添加到类加载器中 . 例如,使用 URLClassLoader.addURL . 但是,如果一个类无法加载(因为,比如说,你没有添加它),那么它将永远不会加载到该类加载器实例中 .

  • 79

    这对我有用:

    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");
    
  • 2

    我被要求构建一个能够在运行时加载新代码的java系统

    您可能希望将系统基于OSGi(或者至少需要花费很多时间),这正是针对这种情况而制定的 .

    与类加载器混淆是非常棘手的业务,主要是因为类可见性如何工作,并且您不希望以后遇到难以调试的问题 . 例如,在许多库中广泛使用的Class.forName()在碎片类加载器空间上不能很好地工作 .

  • 8

    我google了一下,发现这段代码here

    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);
    

    有人可以就这种方法分享意见/评论/答案吗?

  • 34

    使用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;
    }
    

相关问题