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

Java 如何在运行时加载jar文件,java,jar,runtime,classloader,Java,Jar,Runtime,Classloader,我被要求构建一个java系统,该系统能够在运行时加载新代码(扩展)。 在代码运行时,如何重新加载jar文件?或者如何装入新的罐子 显然,由于恒定的启动时间很重要,我想添加在运行时重新加载现有类的功能(如果它不会使事情变得太复杂的话) 我应该注意什么? (将其视为两个不同的问题——一个是关于在运行时重新加载类,另一个是关于添加新类)。我在谷歌上搜索了一下,发现了以下代码: 任何人都可以分享关于这种方法的意见/评论/答案吗?用现有数据重新加载现有类可能会破坏一切 您可以相对轻松地将新代码加载到新类加

我被要求构建一个java系统,该系统能够在运行时加载新代码(扩展)。 在代码运行时,如何重新加载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();
ClassLoader=URLClassLoader.newInstance(
新URL[]{yourURL},
getClass().getClassLoader()
);
Class clazz=Class.forName(“mypackage.MyClass”,true,loader);
等级
我被要求构建一个java系统,该系统能够在运行时加载新代码

您可能希望将您的系统建立在(或者至少要花很多时间)之上,这正是针对这种情况而设计的

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

这对我很有用:

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

使用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;
}
公共加载引擎(){
查找引擎查找;
收集引擎;
模板引擎模板;
结果:1.实验结果;
试一试{
//ocrengineLookup=Lookup.getDefault();这仅在应用程序的类路径中加载OCREngine
ocrengineLookup=Lookups.metaInfServices(getClassLoaderForExtraModule());//这也会在额外模块中加载OCREngine
ocrengineTemplate=新模板(OCREngine.class);
ocrengineResults=ocrengineLookup.lookup(ocrengineTemplate);
ocrengines=ocrengineResults.allInstances();//所有ocrengines必须实现OCREngine中定义的接口。有关详细信息,请参考Implementation org.openide.util.Lookup的指南
}捕获(例外情况除外){
}
}
公共类加载器getClassLoaderForExtraModule()引发IOException{
列表URL=新的ArrayList(5);
//foreach(filepath:external file*.JAR)和每个外部文件*.JAR,执行以下操作
File jar=新文件(filepath);
JarFile jf=新的JarFile(jar);
add(jar.toURI().toURL());
Manifest mf=jf.getManifest();//如果jar在其清单中有类路径,则添加其条目
if(mf
!=空){
字符串cp=
mf.getMainAttributes().getValue(“类路径”);
如果(cp
!=空){
用于(字符串cpe:cp.split(\\s+)){
文件库=
新文件(jar.getParentFile(),cpe);
add(lib.toURI().toURL());
}
}
}
ClassLoader cl=ClassLoader.getSystemClassLoader();
如果(URL.size()>0){
cl=新的URLClassLoader(URL.toArray(新的URL[URL.size()]),ClassLoader.getSystemClassLoader());
}
返回cl;
}

jarurl用于指向带有jar文件的资源。您希望将整个jar文件传递给URLClassLoader。(不幸的是,JAR中的JAR被破坏了。)修复了链接(或者更确切地说,谷歌搜索了“getJarFileToLoadFrom”,并找到了另一个早于我的问题的代码副本:“最终一致”的“internet”方法),如果我最初的类加载器加载了线程池和其他资源之类的东西,这不意味着第二个类加载器加载的新类将无法访问这些资源吗?我没有为URLClassLoader指定父类,所以它将只使用系统(我将修复)。这意味着它仍然能够访问类路径上的类。如果你想分享东西,可以使用公共类加载器(可能是Java lib的引导类加载器)中定义的类型来传递引用。我遗漏了一点:为什么class.newInstance()是“邪恶的”?Ryan,我把这作为一个新问题发布了-请看:根据而不是使用
.toURL()
使用
.toURI().toURL()关于重新加载现有类,考虑这个相关的问题:-你喜欢它复杂化。用OSGi,你可以1。在运行时替换jar。2.当应用程序的不同部分取决于不同的版本时,请保留同一jar的多个版本。3.其他功能,如配置管理、服务工厂等。
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;
}