Pregunta

    

Esta pregunta ya tiene una respuesta aquí:

         

Me pidieron que creara un sistema java que tuviera la capacidad de cargar nuevo código (expansiones) mientras se ejecuta. ¿Cómo vuelvo a cargar un archivo jar mientras se ejecuta mi código? o ¿cómo cargo un nuevo jar?

Obviamente, dado que el tiempo de actividad constante es importante, me gustaría agregar la capacidad de volver a cargar las clases existentes mientras está en él (si no complica demasiado las cosas).

¿Cuáles son las cosas que debo tener en cuenta? (piense en esto como dos preguntas diferentes: una con respecto a la recarga de clases en tiempo de ejecución y la otra con respecto a agregar nuevas clases).

¿Fue útil?

Solución

Recargar clases existentes con datos existentes es probable que rompa las cosas.

Puede cargar código nuevo en cargadores de clases nuevos con relativa facilidad:

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

Los cargadores de clases que ya no se usan pueden recolectarse basura (a menos que haya una pérdida de memoria, como suele ser el caso con el uso de ThreadLocal, controladores JDBC, java.beans , etc.).

Si desea conservar los datos del objeto, le sugiero un mecanismo de persistencia como la serialización, o lo que sea que esté acostumbrado.

Por supuesto, los sistemas de depuración pueden hacer cosas más elegantes, pero son más hacky y menos confiables.

Es posible agregar nuevas clases en un cargador de clases. Por ejemplo, usando URLClassLoader.addURL . Sin embargo, si una clase no se carga (porque, por ejemplo, no la ha agregado), nunca se cargará en esa instancia del cargador de clases.

Otros consejos

Esto funciona para mí:

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 pidieron que creara un sistema java que tenga la capacidad de cargar un nuevo código mientras se ejecuta

Es posible que desee basar su sistema en OSGi (o al menos tome mucho en it), que se hizo exactamente para esta situación.

Jugar con cargadores de clases es un asunto realmente complicado, principalmente debido a cómo funciona la visibilidad de la clase, y no desea tener problemas difíciles de depurar más adelante. Por ejemplo, Class.forName () , que se usa ampliamente en muchas bibliotecas, no funciona demasiado bien en un espacio fragmentado de cargador de clases.

Busqué en Google un poco y encontré este código aquí :

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

¿Alguien puede compartir opiniones / comentarios / respuestas con respecto a este enfoque?

Use org.openide.util.Lookup y ClassLoader para cargar dinámicamente el complemento Jar, como se muestra aquí.

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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top