Comment charger un fichier jar lors de l’exécution

On m’a demandé de créer un système Java capable de charger un nouveau code (extensions) pendant l’exécution. Comment recharger un fichier jar pendant que mon code est en cours d’exécution? ou comment charger un nouveau pot?

Evidemment, comme il est important d’avoir un temps de fonctionnement constant, j’aimerais append la possibilité de recharger les classes existantes (si cela ne complique pas trop les choses).

Quelles sont les choses que je devrais rechercher? (considérez-le comme deux questions différentes – l’une concernant le rechargement des classes à l’exécution, l’autre concernant l’ajout de nouvelles classes).

Le rechargement de classes existantes avec des données existantes risque de casser des choses.

Vous pouvez charger le nouveau code dans de nouveaux chargeurs de classe relativement facilement:

ClassLoader loader = URLClassLoader.newInstance( new URL[] { yourURL }, getClass().getClassLoader() ); Class clazz = Class.forName("mypackage.MyClass", true, loader); Class runClass = clazz.asSubclass(Runnable.class); // Avoid Class.newInstance, for it is evil. Constructor ctor = runClass.getConstructor(); Runnable doRun = ctor.newInstance(); doRun.run(); 

Les chargeurs de classes qui ne sont plus utilisés peuvent être récupérés (sauf en cas de fuite de mémoire, comme c’est souvent le cas avec ThreadLocal, les pilotes JDBC, java.beans , etc.).

Si vous souhaitez conserver les données d’object, je suggère un mécanisme de persistance tel que la sérialisation, ou tout ce à quoi vous êtes habitué.

Bien entendu, les systèmes de débogage peuvent faire des choses plus sophistiquées, mais ils sont plus complexes et moins fiables.

Il est possible d’append de nouvelles classes dans un chargeur de classes. Par exemple, en utilisant URLClassLoader.addURL . Cependant, si une classe ne parvient pas à se charger (parce que, par exemple, vous ne l’avez pas ajouté), elle ne se chargera jamais dans cette instance du chargeur de classe.

Cela fonctionne pour moi:

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

On m’a demandé de construire un système java capable de charger un nouveau code en cours d’exécution.

Vous voudrez peut-être baser votre système sur OSGi (ou du moins en prendre beaucoup), ce qui a été fait exactement pour cette situation.

Les messageries avec des chargeurs de classe sont vraiment délicates, principalement à cause du fonctionnement de la visibilité des classes, et vous ne voulez plus vous retrouver avec des problèmes difficiles à déboguer par la suite. Par exemple, Class.forName () , qui est largement utilisé dans de nombreuses bibliothèques, ne fonctionne pas bien sur un espace de chargement de classes fragmenté.

J’ai googlé un peu, et j’ai trouvé ce code ici :

 File file = getJarFileToLoadFrom(); Ssortingng lcStr = getNameOfClassToLoad(); URL jarfile = new URL("jar", "","file:" + file.getAbsolutePath()+"!/"); URLClassLoader cl = URLClassLoader.newInstance(new URL[] {jarfile }); Class loadedClass = cl.loadClass(lcStr); 

Quelqu’un peut-il partager des opinions / commentaires / réponses concernant cette approche?

Utilisez org.openide.util.Lookup et ClassLoader pour charger dynamicment le plug-in Jar, comme illustré ici.

 public LoadEngine() { Lookup ocrengineLookup; Collection 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 urls = new ArrayList(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 ensortinges if (mf != null) { Ssortingng cp = mf.getMainAtsortingbutes().getValue("class-path"); if (cp != null) { for (Ssortingng 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; }