Pergunta

Esta pergunta já tem uma resposta aqui:

Foi-me pedido para construir um sistema java, que terá a capacidade de carregar o novo código (expansões) durante a execução.Como faço para re-carregar um arquivo jar, enquanto o meu código está sendo executado?ou como faço para carregar um novo frasco?

Obviamente, desde que a constante de tempo é importante, eu gostaria de adicionar a capacidade de re-carga de classes existentes, enquanto que no-lo (se ele não complicar muito as coisas).

Quais são as coisas que eu deveria olhar para fora?(pense nisso como dois aspectos diferentes - uma relação recarregar as classes em tempo de execução, o outro sobre a adição de novas classes).

Foi útil?

Solução

Recarregar as classes existentes com os dados existentes são propensos a quebrar as coisas.

Você pode carregar o código novo em nova classe de gestores de forma relativamente fácil:

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

Classe carregadores não é mais usado pode ser lixo coletado (a menos que haja um vazamento de memória, como é frequentemente o caso com o uso de ThreadLocal, drivers JDBC, java.beans, etc.).

Se você deseja manter os dados do objeto e, em seguida, sugiro um mecanismo de persistência, como Serialisation, ou o que quer que você está acostumado.

É claro que a depuração de sistemas pode fazer coisas bem legais que, mas são mais hacky e menos confiável.

É possível adicionar novas classes em um carregador de classe.Por exemplo, usando URLClassLoader.addURL.No entanto, se uma classe não carregar, pois, dizer, que você ainda não tiver adicionado a ele), então ele nunca vai carregar no carregador de classe de instância.

Outras dicas

Isso funciona para mim:

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

Me pediram para construir um sistema Java que tenha a capacidade de carregar um novo código enquanto executava

Você pode querer basear seu sistema em Osgi (Ou pelo menos aceite muito), que foi feito para exatamente essa situação.

Mudar com os carregadores de classes é um negócio realmente complicado, principalmente por causa de como funciona a visibilidade da classe, e você não deseja ter problemas difíceis de fugir mais tarde. Por exemplo, Class.ForName (), que é amplamente utilizado em muitas bibliotecas não funciona muito bem em um espaço de carregador de classe fragmentado.

Eu pesquisei um pouco no Google e encontrei este código aqui:

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

Alguém pode compartilhar opiniões/comentários/respostas sobre essa abordagem?

Use org.openide.util.lookup e classe de classe para carregar dinamicamente o plug -in JAR, como mostrado aqui.

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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top