2009-11-10 14 views
15

Tengo un archivo JAR que contiene una aplicación y archivos de configuración para esa aplicación. La aplicación carga archivos de configuración desde classpath (usando ClassLoader.getResource()), y tiene sus dependencias completamente satisfechas usando los archivos de configuración integrados en el archivo JAR.¿Puedo usar classpath para reemplazar un archivo en un jar que se está ejecutando?

En ocasiones deseo que la aplicación se ejecute con una configuración ligeramente diferente (específicamente quiero anular la URL JDBC para apuntar a una base de datos diferente) así que creo un nuevo archivo de configuración, almacénelo en la estructura de directorios correcta (lo que significa que en un directorio /config de una entrada de ruta de clase), y quiero hacer algo como esto:

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

Pero no puede obtener la ruta de clase para tener la entrada new-config camino ante el contenido del JAR aplicación. ¿Está codificado que el contenido del JAR sea siempre lo primero en el classpath?

+0

¿Usted ha intentado poner la configuración fuera de frasco, en su propio archivo jar en una ruta relativa a application.jar (../conf/config.jar)? Si lo haces, creo que puedes establecer la ruta de clases que apunta a ese archivo de configuración en el manifiesto de la aplicación y puedes establecer la nueva configuración cambiando config.jar. Ojalá tuviera más tiempo para hacer una demostración para confirmar mi respuesta, pero no puedo ... así que lo escribí como un comentario – JuanZe

+0

¿Quieres decir, en lugar de dentro del JAR? – Guss

+0

sí, en lugar de dentro del mismo contenedor que la aplicación, poner la configuración dentro de un segundo contenedor ... – JuanZe

Respuesta

20

¿Por qué no llamar a la aplicación sin especificar jar y en su lugar nombrar la clase principal de la aplicación de forma explícita? Esto le permitirá colocar tanto su configuración nueva como application.jar en el classpath en el orden requerido:

p. (Asumiendo "nueva-config" es un directorio que contiene el archivo de propiedades sobrescritos)

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

Creo que el nombre de la clase principal se puede encontrar en el archivo MANIFEST.MF dentro de la jarra ....

+2

El principal problema es que realmente no uso el argumento -cp, pero especifico el classpath en el archivo de manifiesto, ya que la aplicación requiere muchos otros JAR externos, extrayendo todo lo que será bastante propenso a errores. Pero apuesto a que puedo escribir un script que extraiga el classpath del manifiesto y construya una línea de comando relevante automáticamente, por lo que esta es probablemente la respuesta que usaré. – Guss

1

Puede que no sea posible utilizando solo CLASSPATH. Hay formas de hacer que la llamada al ClassLoader.getResource() use una ruta estática para encontrar el recurso. Si está haciendo eso, está pasando por alto CLASSPATH.

3

El archivo JAR especificado por la opción -jar anula todos los demás valores.

En general, tendrías que hacerlo con un archivo de configuración externo o crear tu propia solución con 0 ClassLoader.getResource().

se utiliza una solución personalizada para resolver este - cargamos las propiedades internas de este modo:

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

A continuación, cargar el archivo externo de la misma manera y sobrescribir los valores internos con los externos.

Para información sobre cómo funciona la carga de clases, véase:

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

+0

Este es de hecho el problema. Entiendo que no hay forma de evitarlo, excepto lanzar la aplicación de una manera diferente, como lo sugiere alasdairg, o escribir algún código de carga personalizado. Gracias. – Guss

13

cuando se utiliza la opción -jar para iniciar la aplicación:

... el archivo JAR es la fuente de todas las clases de usuarios , y otros configuración de clase de usuario de ruta son ignorados.

como se describe here. Una solución alternativa sería especificar el classpath en el manifiesto del archivo jar para incluir la ruta adicional (descrita en here).

Sin embargo, dado que solo está hablando de modificar la configuración, es posible que desee adoptar un enfoque diferente que no dependa de la ruta de clases. Por ejemplo, normalmente configuro mis aplicaciones a través de Spring utilizando archivos de propiedades para determinar la ubicación de las bases de datos, etc. La configuración de My Spring es uniforme en entornos de prueba, QA y Live, pero transfiero un archivo de propiedad diferente como argumento de línea de comando al iniciar la aplicación .

configuración del resorte de fragmentos

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

archivo de propiedades de fragmentos

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

Pasar el archivo de configuración como un parámetro opcional es una buena idea, pero mi aplicación actualmente acepta bastantes parámetros y agregar otro será problemático para los usuarios. Gracias por la respuesta. – Guss

+0

¿Cómo se inicia su aplicación? Hubiera pensado que los parámetros pasados ​​se ocultarían al usuario al iniciar la aplicación a través de Webstart, script .bat o .sh, etc. – Adamski

+0

No: los usuarios lanzan la aplicación desde la línea de comando, pasando los parámetros necesarios: fechas , archivos para procesar, etc. – Guss

Cuestiones relacionadas