2010-07-17 7 views
4

J'ai un fichier jar (disons app.jar) dans un certain endroit disponible en tant que fichier/flux à partir d'un serveur http. Le problème est que app.jar est lui-même un fichier jar fréquemment mis à jour régulièrement mis à jour sur le serveur. J'ai un autre fichier jar (disons load.jar) qui est simplement téléchargeable par n'importe quel utilisateur. Lors de l'exécution, l'utilisateur exécute load.jar, ce qui est nécessaire pour charger le fichier app.jar dans un processus séparé en gardant le fichier app.jar en mémoire (pas de mise en cache sur le disque), puis exécuter le fichier app.jar et se terminer .pot). Est-ce possible? Toute aide est grandement appréciée. Merci d'avance. Cordialement, KTEn mémoire jar/exécution de fichier de classe

--------------------------- Mise à jour.

Bonjour,

Merci à tous pour la réponse. Cependant, je suppose que je n'ai pas donné une image complète. Une image link text est jointe illustrant le scénario. 4 jarres (les exécuteurs communs réels) sont hébergés sur un serveur central. Ceux-ci sont mis à jour fréquemment (probablement 3-4 fois par jour initialement à une fois par jour finalement). Un serveur local de l'un des membres est hébergé et initialisé. Le lanceur sur le serveur local télécharge tous les 4 binaires et le garde en mémoire - aucun cache sur le disque. Ces fichiers jar sont auto-suffisants et ne dépendent d'aucune bibliothèque sur le "serveur local" - ils invoquent en fait des fichiers jar du "serveur local". Le pot "client" est finalement hébergé avec le "serveur local" et transmis à ses clients à la demande via webapp par le "serveur local". En outre, le programme de lancement doit quitter en appelant le fichier principal jar téléchargé du serveur dans une machine JVM distincte.

Cordialement, KT

Répondre

3

OK. Avant de mettre le lien vers l'article szegedi dans ma réponse précédente (honnête), j'ai prototypé un jar-lanceur capable de gérer les URLs. Comme l'a dit l'auteur, ce n'était pas difficile, n'est probablement pas complet. Ci-joint.Je pense que c'est 1/3 de ce dont tu as besoin. Votre nom d'utilisateur dit (quelque chose comme):

java jar load.jar http://localhost:8080/app.jar

load.jar a deux rôles: (1) JarLauncher invoquer (ci-dessous) comme classe principale (2) servir app.jar sur un port localhost (avant d'appeler le JarLauncher). load.jar lit donc ses arguments pour déterminer quelle application exécuter. Enfin (le bit dur): vous devez faire en sorte que URLClassLoader ne frappe pas le disque temporaire. Comme l'a dit l'article de Szegedi, ce n'est pas facile. Alternativement, vous pouvez écrire votre propre classloader réseau qui ne cache pas le disque, comme ma première suggestion chargeant l'URL en mémoire comme un byte-stream à partir d'une connexion URL, le décodant en JarInputStream et satisfaisant les appels à loadClass/findResource à partir de ce flux en mémoire.

Vous avez beaucoup de travail devant vous. Bonne chance.

Toutes mes excuses pour la taille du texte de la licence, mais il vous permet de faire ce que vous voulez avec le code tant que vous ne me blâmez pas (BSD).

--simon.


 

/* 
* One-JAR(TM) (http://www.simontuffs.com/one-jar). Copyright (c) 2004-2010, 
* P. Simon Tuffs ([email protected]). All rights reserved. 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions are met: 
* 
* Redistributions of source code must retain the above copyright notice, this 
* list of conditions and the following disclaimer. 
* 
* Redistributions in binary form must reproduce the above copyright notice, 
* this list of conditions and the following disclaimer in the documentation 
* and/or other materials provided with the distribution. 
* 
* Neither the name of P. Simon Tuffs, nor the names of any contributors, 
* nor the name One-JAR may be used to endorse or promote products derived 
* from this software without specific prior written permission. 
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
* POSSIBILITY OF SUCH DAMAGE. 
* 
* Including this file inside the built One-JAR file conforms with these terms. 
*/ 

import java.lang.reflect.Method; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.jar.JarInputStream; 

/** 
* Programmatic equivalent of what happens when you say "java -jar <jar-file.jar>". 
* A better solution to debugging/running Jar files inside an IDE. 
* @author simon 
* 
*/ 
public class JarLauncher { 

    public static URL getURL(String string) throws MalformedURLException { 
     try { 
      return new URL(string); 
     } catch (MalformedURLException x) { 
      return new URL("file:" + string); 
     } 
    } 

    public static void main(String args[]) throws Exception { 
     if (args.length < 1) { 
      System.out.println("Usage: java [-Dkey=value...] JarLauncher <jar-file.jar>"); 
      System.exit(1); 
     } 
     String jar = args[0]; 
     args = Arrays.copyOfRange(args, 1, args.length); 
     List<URL> urls = new ArrayList<URL>(); 
     // Main jar on the URL path. 
     // Dig out the main class. 
     urls.add(getURL(jar)); 
     URL jarurl = urls.get(0); 
     JarInputStream jis = new JarInputStream(jarurl.openStream()); 
     String main = jis.getManifest().getMainAttributes().getValue("Main-Class"); 
     // OK to split on space, because embedded space is %20 
     String classpaths[] = jis.getManifest().getMainAttributes().getValue("Class-Path").split(" "); 
     for (String classpath: classpaths) { 
      urls.add(getURL(classpath)); 
     } 
     URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[0])); 
     Class<?> cls = loader.loadClass(main); 
     Thread.currentThread().setContextClassLoader(loader); 
     Method m = cls.getMethod("main", new Class[]{new String[0].getClass()}); 
     m.invoke(null, new Object[]{args}); 

    } 

} 

0

Avez-vous eu un coup d'œil à la classe URLClassLoader encore?

Le JarClassloader ici pourrait être utile: http://www.java.happycodings.com/Other/code27.html

+0

(Comme il arrive 'URLClassLoader' met toujours en cache pour le disque, car sans raison valable.) –

2

Je proposerai un coup d'oeil à http://jcloader.sourceforge.net/

Cela a une meilleure flexibilité et est assez riche en fonctionnalités.

JarClassLoader jcl = new JarClassLoader(); 

    //Loading classes from different sources 
    jcl.add("myjar.jar"); 
    jcl.add(new URL("http://myserver.com/myjar.jar")); 
    jcl.add(new FileInputStream("myotherjar.jar")); 
    jcl.add("myclassfolder/"); 

    //Recursively load all jar files in the folder/sub-folder(s) 
    jcl.add("myjarlib/"); 

    JclObjectFactory factory = JclObjectFactory.getInstance(); 

    //Create object of loaded class 
    Object obj = factory.create(jcl, "mypack.MyClass"); 
2

De plus Edit:

Je scrutais le web et suis tombé sur cet excellent article qui peut également avoir une incidence sur votre question: http://www.szegedi.org/articles/remotejars.html

Dans ce cas, la plupart de ce que j'ai écrit ci-dessous est hors de propos , mais je vais le laisser de toute façon juste au cas où.

Edit:

Ok, je pense que je vais avoir une meilleure idée de vos besoins. Les exigences sont délicates, alors laissez-moi vous dire ce que je pense que vous essayez de faire, et ensuite je verrai quelles solutions cela suggère. Je vais probablement me tromper, alors on recommence.

Exigences:

Un mécanisme de mise en cache distribuée pour servir les applications webstart. Les applications (.jars) changent régulièrement. Ils sont autonomes.Vous voulez avoir un cache local capable de servir les fichiers jar Webstart obtenus à partir d'un serveur central, en les gardant en mémoire. Je ne comprends pas vos exigences pour Exit.

Solutions? Ce que vous cherchez peut-être est un serveur Web qui peut héberger une application Web qui lira en mémoire les jars d'application mis à jour, puis les servira au lanceur Webstart. Vous devrez utiliser un serveur Web tel que Jetty/Tomcat, et écrire une simple application web pour l'exécuter. La webapp interrogera le serveur central pour les mises à jour de l'application, et mettra les jars de l'application à la disposition de webstart via les URL qu'elle sert. Il est probablement plus logique d'interroger le serveur central que de faire en sorte que le serveur central envoie de nouvelles applications aux serveurs locaux pour des raisons de pare-feu et d'évolutivité.

Je ne connais pas de webapps prêtes à l'emploi qui le font, il y en a peut-être une.

Mais comme je l'ai dit, je n'ai probablement toujours pas compris. Exigences: doit les aimer. Je vais faire quelques hypothèses dans cette réponse, en fonction de votre question. Il semble que vous souhaitiez mettre en cache "app.jar" depuis la machine distante, pour la durée de vie de "load.jar" sur la machine locale, afin de permettre d'isoler "load.jar" des modifications apportées à "app.jar" "Au cours de sa vie. Cela semble être une bonne idée: je m'attendrais à ce que si vous utilisez un URLClassLoader pour apporter "app.jar" dans l'espace "load.jar", alors une mise à jour à mi-chemin de l'exécution pourrait faire des ravages.

Il semble aussi que vous ne voulez pas que "load.jar" fasse une copie sur disque de "app.jar" - Je pense que c'est un objectif raisonnable: qui veut avoir de vieux fichiers jar éparpillés sur la machine? qui veut des problèmes d'autorisation liés à la tentative d'écriture de fichiers temporaires? Etant donné ces objectifs, vous devez trouver ou implémenter un chargeur de classe qui crée un instantané de "app.jar" lorsque "load.jar" frappe une classe à l'intérieur. Ce n'est pas difficile: j'ai dû faire quelque chose de similaire dans mon JarClassLoader One-JAR, qui charge les fichiers Jar depuis l'intérieur des fichiers Jar. Au démarrage, il charge tous les octets trouvés dans la mémoire, puis résout les classes à la demande en utilisant ce magasin de mémoire. Bien que moins efficace que le chargement paresseux, il est rapide et stable et résoudrait votre problème.

Malheureusement, One-JAR ne permet pas aux ressources réseau (ou fichier) d'être mises en cache de cette manière. Il utilise la délégation via un chargeur de classe d'URL normal, ce qui le rendrait pas en cache vos ressources distantes.

Je vous suggère de jeter un oeil sur le référentiel CVS: http://one-jar.cvs.sourceforge.net/viewvc/one-jar/one-jar/src/com/simontuffs/onejar/JarClassLoader.java?revision=1.58&view=markup

autour de la ligne 678. Ne vous laissez pas intimidés par la taille de cette classe, est un groupe de cas particuliers à traiter, ainsi, des cas particuliers. Si je devais créer quelque chose à partir de zéro, je sous-classerais URLClassLoader, remplacerait les méthodes loadClass, getResource, et findResource (voir par exemple la ligne 281 où One-JAR fait cela pour ses propres inversion de classes), dans la mise en cache de bytecode en chargeant le "app.jar" entier dans la mémoire comme hashmap de tableau d'octets indexé par les clés de nom de classe/ressource (ceci est One-JAR encore), et alors vous seriez mis en cache en mémoire.

J'espère que cela aide.

--simon.

Questions connexes