java - plus - ¿Cómo proporcionar una configuración de contexto para una aplicación web en Tomcat?
tomee (6)
Tengo una aplicación web que depende de algunos recursos y parámetros que se configurarán después de instalarla, como una conexión JDBC.
Lo que se me ocurrió es proporcionar un META-INF/context.xml
que se copia en [engine-name]/[server-name]/[app-name].xml
por Tomcat cuando despliegue la aplicación. De esta forma, todo lo que proporciono es un archivo war que se puede copiar en la carpeta appBase (webapps). La documentación de Tomcat says si hay tal archivo no se sobrescribirá, lo que es realmente genial, ya que los cambios realizados después de la implementación no se perderán.
Pero aquí hay un problema sutil: desde que implementamos la aplicación copiando en el directorio de webapps, Tomcat primero desinstala la aplicación existente así como también el archivo de configuración. De esta forma, el archivo de configuración se perderá / sobrescribirá, lo que no es deseable. Tomcat won''t modificará este comportamiento hasta donde yo sé.
La pregunta es: ¿hay alguna manera de evitar este problema instalando la aplicación de forma que Tomcat no elimine el archivo de configuración existente? O, ¿hay una mejor forma de empaquetar la aplicación?
Tenga en cuenta que no deseamos establecer autoDeploy en falso y no podemos utilizar la intervención humana para la instalación (lo cual excluye el uso de la aplicación web Tomcat Manager).
Si obtengo el archivo de configuración del archivo .war y lo copio por separado como [engine-name]/[server-name]/[app-name].xml
, Tomcat lo asociará con mi aplicación y lo eliminará una vez que copie un nuevo archivo .war.
Otra suposición es: no sabemos de antemano los valores de la configuración. Solo proporcionaremos una configuración de muestra (un marcador de posición, si lo desea) mientras que la configuración real se realizará en un momento posterior (no necesariamente en el tiempo de instalación).
Gracias
@ n0rm1e: no estoy seguro si tomcat proporciona algún tipo de solución para su problema. Pero una posible solución puede ser: - crear un script ant con los siguientes pasos:
i) Verifique la existencia del archivo .xml en el directorio [nombre del motor] / [nombre del servidor]. Si existe, tome una copia de seguridad de esto / cambie el nombre.
ii) copie su archivo war a webapps de tomcat. Reinicie el servidor Tomcat.
iii) copiar el archivo de configuración de copia de seguridad al directorio [nombre del motor] / [nombre del servidor]
Al referirse a la documentación de says :
En el archivo $ CATALINA_HOME / conf / context.xml: la información del elemento Contexto será cargada por todos los webapps
Podría probar fácilmente este enfoque, podría funcionar, pero no estoy seguro de si esta es una buena solución, especialmente si está ejecutando varias aplicaciones web en Tomcat.
Así es como podemos gestionar la externalización del contexto de lawebapp desde el archivo .WAR
- Coloque su archivo .WAR en algún lugar fuera de tomcat
- Cree un archivo $ APP_NAME.xml en el directorio $ TOMCAT_HOME / conf / [Engine] / [Host] /.
- Ahora el archivo "$ APP_NAME.xml" que acabamos de crear necesita tener una definición de contexto y parámetros + Cualquier variable de entorno que desee específica para ese contexto.
Por ejemplo, tengo una aplicación web llamada VirtualWebApp.
Crearé un archivo como VirtualWebApp.xml con la siguiente definición de contexto:
<Context docBase="/home/appBase/VirtualWebApp" path="/VirtualWebApp" reloadable="true">
<Environment name="webservice.host" type="java.lang.String" value="1.2.3.4" />
<Environment name="webservice.port" type="java.lang.String" value="4040" />
</Context>
Para acceder a estas variables de entorno, debe escribir el código siguiente (búsqueda simple):
InitialContext initialContext = new javax.naming.InitialContext();
host = (String)initialContext.lookup("java:comp/env/webservice.host");
port = (String)initialContext.lookup("java:comp/env/webservice.port");
La solución es simple: no coloque la configuración en su context.xml.
Aquí hay una solución que usamos (que funciona bien para una cantidad de clientes externos diversos):
Tenemos una sola guerra que se usará en múltiples entornos, webapp.war. Tenemos tres entornos, desarrollo, integración y producción. La integración y la producción están en el sitio del cliente. No conocemos las contraseñas y rutas de archivos para los sitios de integración y producción de clientes.
Usamos una combinación de dos cosas: búsqueda JNDI para material de base de datos y archivos de propiedades externas.
En el context.xml
que se entrega en la guerra, tenemos un ResourceLink
<ResourceLink name="jdbc/webapp"
global="uk.co.farwell.webapp.datasource.MySqlDataSource" />
Esto proporciona una referencia a una fuente de datos definida globalmente, que se define en server.xml
para Tomcat.
<Resource auth="Container"
driverClassName="com.mysql.jdbc.Driver"
name="uk.co.farwell.webapp.datasource.MySqlDataSource"
password="xxx" url="xxx" username="fff" />
Por lo tanto, los detalles de la base de datos pueden modificarse editando server.xml
sin cambiar webapp.war
. Fundamentalmente, esto solo debe hacerse una vez para cada servidor, no en redespliegue.
En nuestra configuración de primavera, para definir el dataSource
tenemos:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/webapp" />
Para otras propiedades, tenemos un archivo global application.properties que se entrega junto con webapp.war, pero no es parte de la guerra. Esto es referenciado por una -D
en la línea de comando para iniciar Tomcat. -Duk.co.farwell.webapp.applicationDir="/usr/xxx/fff"
. Recogemos la definición y leemos el archivo de propiedades. Las cosas de la base de datos también se podrían hacer de esta manera, pero perderíamos la agrupación hecha por Tomcat.
Otra cosa: no tenemos que reconstruir si los servidores se trasladan, o si las máquinas se cambian por alguna razón. Este es un asunto para el cliente y su personal de infraestructura.
Me las arreglé para resolver este problema de alguna manera.
1- Instalar un directorio de WAR explotado en algún lugar fuera de la base de datos de Tomcat, supongamos que está en /usr/local/MyApp
. [Puede usar un archivo WAR para este paso en lugar del directorio WAR, si su aplicación se ejecuta a partir de una guerra no explotada.]
2- Copie el archivo de configuración de contexto en el [tomcat.conf]/[engine]/[hostname]
, llamémoslo MyApp.xml
. Este archivo apuntará a la ubicación de la aplicación:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Context configuration file for my web application -->
<Context docBase="/usr/local/MyApp" privileged="true" antiResourceLocking="false" antiJARLocking="false">
<Resource name="jdbc/myapp-ds" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000" username="XXX" password="XXX"
driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb" />
</Context>
3- Ahora puede ir y modificar el archivo de configuración.
4- Actualiza la aplicación copiando la nueva versión de tu aplicación en / usr / local / MyApp
Notas:
a) Esta solución también se aplica a un archivo .war no expandido, pero dado que usamos Log4JConfigListener de Spring, no se ejecutará desde un archivo .war sin explotar. Tomcat no destruye archivos .war puestos fuera de la carpeta appBase (webapps).
b) Este enfoque no le impide tener context.xml en /usr/local/MyApp/META-INF/context.xml, ya que Tomcat no lo usará en esta configuración. Puedes usarlo en tu entorno de desarrollo, donde puedes volcar tu archivo .war en la carpeta appBase (webapps).
Esto es lo que tengo hasta ahora, aún buscando mejores soluciones.
No sé cómo modificar el comportamiento de Tomcat pero podría pensar en 2 soluciones diferentes:
- diferentes scripts de compilación (parametrizados) para cada entorno, para que defina un parámetro llamado
env
para sus scripts de compilación y, según el valor, ubique el entorno específico.textcontext.xml
en su WAR durante la compilación. - Cree una secuencia de comandos de
install
para cada entorno que primero vuelve awebapps
el archivo WAR (lo coloca en el directoriowebapps
) y luego realiza modificaciones en la instalación de Tomcat dependiendo del entorno, por ejemplo, diferentes nombres de host para JDBC DataSource encontext.xml
.
Hago un uso intensivo de este último enfoque, ya que funciona en entornos empresariales. Las políticas de separación de funciones a menudo prohíben que el equipo de desarrollo conozca, por ejemplo, contraseñas de bases de datos de producción. La opción n. ° 2 resuelve este problema porque solo las operaciones de TI tienen acceso a los scripts de instalación específicos del entorno una vez que se han creado.