有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在运行时加载jar文件

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

显然,由于恒定的启动时间很重要,我想添加在运行时重新加载现有类的功能(如果不会使事情变得太复杂的话)

我应该注意什么? (可以将其视为两个不同的问题——一个关于在运行时重新加载类,另一个关于添加新类)


共 (5) 个答案

  1. # 1 楼答案

    这对我很有用:

    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. # 2 楼答案

    I was asked to build a java system that will have the ability to load new code while running

    你可能想把你的系统建立在OSGi的基础上(或者至少要花很多时间),这正是为这种情况而设计的

    处理类加载器是一件非常棘手的事情,主要是因为类可见性是如何工作的,而且您不想在以后遇到难以调试的问题。例如,在许多库中广泛使用的Class.forName()在零碎的类加载器空间中工作不太好

  3. # 3 楼答案

    使用组织。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;
    }
    
  4. # 4 楼答案

    我在谷歌上搜索了一下,发现了以下代码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);   
    

    有人能分享关于这种方法的意见/评论/答案吗

  5. # 5 楼答案

    用现有数据重新加载现有类很可能会导致崩溃

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

    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。然而,如果一个类未能加载(比如说,因为您没有添加它),那么它将永远不会加载到该类加载程序实例中