2009-11-10 11 views
15

J'ai un fichier JAR qui contient une application ainsi que des fichiers de configuration pour cette application. L'application charge les fichiers de configuration à partir du classpath (en utilisant ClassLoader.getResource()), et ses dépendances sont complètement satisfaites en utilisant les fichiers de configuration cuits dans le fichier JAR. À l'occasion, je souhaite que l'application soit exécutée avec une configuration légèrement différente (en particulier, je souhaite remplacer l'URL JDBC pour qu'elle pointe vers une base de données différente) afin de créer un nouveau fichier de configuration. ce qui signifie dans un répertoire /config d'une entrée de classpath), et je veux faire quelque chose comme ceci:Puis-je utiliser le classpath pour remplacer un fichier dans un fichier jar en cours d'exécution?

java -cp new-config:. -jar application.jar 

Mais je ne peux pas obtenir le classpath d'avoir l'entrée du chemin new-config avant le contenu de l'application JAR. Est-ce codé en dur que le contenu du JAR est toujours la première chose sur le classpath?

+0

Avez-vous essayé de mettre la config en dehors de pot, dans son propre fichier jar dans un chemin relatif à application.jar (../conf/config.jar)? Si vous le faites, je pense que vous pouvez définir le chemin de classe pointant vers ce fichier config dans le manifeste de l'application et vous pouvez définir la nouvelle configuration en modifiant le fichier config.jar. Je voudrais avoir plus de temps pour faire une démo pour confirmer ma réponse, mais je ne peux pas ... donc je l'ai écrit comme un commentaire – JuanZe

+0

Vous voulez dire, au lieu de l'intérieur du JAR? – Guss

+0

oui, au lieu de l'intérieur du même pot que l'application, mettre la config dans un second pot ... – JuanZe

Répondre

20

Pourquoi ne pas simplement appeler l'application sans spécifier jar et nom au lieu de l'application classe principale explicitement? Cela vous permettra de mettre à la fois votre new-config et le fichier application.jar sur le chemin de classe dans l'ordre requis:

par exemple. (En supposant que « new-config » est un répertoire contenant les propriétés redéfinies fichier)

java -cp new-config:application.jar Application.Main.Class 

Je crois que le nom de classe principale se trouve dans le fichier MANIFEST.MF à l'intérieur du pot ....

+2

Le problème principal est que je n'utilise pas réellement l'argument -cp mais spécifie le chemin de classe dans le fichier manifeste, car l'application nécessite de nombreux autres JAR externes - en extrayant tout ce qui sera plutôt sujette aux erreurs. Mais je parie que je peux écrire un script qui extrait le classpath du manifeste et construit automatiquement une ligne de commande, donc c'est probablement la réponse que j'utiliserai. – Guss

1

Cela peut ne pas être possible avec le CLASSPATH. Il existe des moyens pour obtenir l'appel à ClassLoader.getResource() utiliser un chemin statique pour trouver la ressource. Si c'est le cas, il contourne le CLASSPATH.

3

L'archive JAR spécifiée par l'option -jar remplace toutes les autres valeurs.

Vous devez généralement le faire avec un fichier de configuration externe ou créer votre propre solution avec ClassLoader.getResource().

Nous utilisons une solution personnalisée pour résoudre ce - on charge les propriétés internes comme ceci:

final Properties p = new Properties(); 
p.load(DefaultConfiguration.class.getResourceAsStream("config.properties")); 

Nous avons ensuite charger le fichier externe de la même manière et écrasent les valeurs internes avec les externes.

Pour info sur le fonctionnement de chargement de classe voir:

http://java.sun.com/javase/6/docs/technotes/tools/findingclasses.html

+0

C'est en effet le problème. Je comprends qu'il n'y a aucun moyen de contourner cela, sauf le lancement de l'application d'une manière différente - comme suggéré par alasdairg, ou en écrivant un code de chargement personnalisé. Merci. – Guss

13

lorsque vous utilisez l'option jar pour lancer votre application:

... le fichier JAR est la source de toutes les classes d'utilisateurs et autres paramètres de chemin classe utilisateur sont ignorées.

comme décrit here. Une solution de contournement consiste à spécifier le chemin de classe dans le manifeste du fichier jar pour inclure le chemin d'accès supplémentaire (décrit here).Toutefois, étant donné que vous ne parlez que de modifier la configuration, vous pouvez choisir une approche différente qui ne dépend pas du chemin de classe. Par exemple, je configure généralement mes applications via Spring en utilisant des fichiers de propriétés pour déterminer l'emplacement des bases de données, etc. Ma configuration Spring est cohérente dans les environnements de test, QA et live mais je passe un fichier de propriétés différent comme argument de ligne de commande .

Configuration Spring Snippet

<bean id="MyDataSource" class="org.springframework.jdbc.datasource.SingleConnectionDataSource"> 
    <property name="url" value="jdbc:microsoft:sqlserver://${dbServer}:${dbPort};DatabaseName=${dbName}"/> 
    <property name="username" value="${dbUserName}"/> 
    <property name="password" value="${dbPassword}"/> 
    <property name="suppressClose" value="false"/> 
</bean> 

propriété fichier Snippet

dbServer=MyServer 
dbPort=1433 
dbName=MyDb 
dbUserName=Me 
dbPassword=foobar 
+0

Passer le fichier de configuration en tant que paramètre facultatif est une bonne idée, mais mon application accepte actuellement pas mal de paramètres et en ajouter un autre sera problématique pour les utilisateurs. Merci pour la réponse si. – Guss

+0

Comment lancez-vous votre application? J'aurais pensé que les paramètres passés seraient cachés à l'utilisateur en lançant l'application via le script Webstart, .bat ou .sh, etc. – Adamski

+0

Non - les utilisateurs lancent l'application eux-mêmes à partir de la ligne de commande, en passant les paramètres requis - dates , les fichiers à traiter, etc – Guss