unica - Patrones de configuración de aplicaciones web Java
cómo desbloquear una aplicación bloqueada por configuracion de seguridad (10)
¿Hay algún patrón o mejores prácticas que se puedan usar para simplificar el cambio de los perfiles de configuración para aplicaciones web Java en múltiples entornos? por ejemplo, URL JDBC, puntos finales SOAP, etc.
Como un poco de contexto para ayudar a aclarar mi pregunta, trabajo con varias aplicaciones web de Java grandes que durante un ciclo de lanzamiento determinado se mueven a través de 6 entornos diferentes; desarrollo, integración, control de calidad, rendimiento y, finalmente, se implementan en múltiples servidores de producción. En cada entorno, la configuración debe cambiar. En este momento, la mayoría de los cambios de configuración para cada implementación se realizan de forma manual, lo cual consume mucho tiempo y está abierto a errores.
¿Hay alguna manera de sacar la intervención manual de este proceso?
Al principio tiene todos los ajustes de configuración que cambian con frecuencia en un solo lugar. Es realmente difícil, si necesita configurar JNDI, editar valores de base de datos y modificar archivos de propiedades, todo al mismo tiempo, para completar la configuración. Prefiera el medio que sea más fácil de editar y también más fácil de verificar que todo esté configurado correctamente. Diría que los archivos de propiedades son la mejor solución. Puede editarlos fácilmente y solo necesita echar un vistazo rápido para ver que todo esté bien. Si opta por los archivos de propiedad, seleccione cuidadosamente una ubicación estándar para ellos y asigne una variable ambiental para la ruta.
También ayuda si tiene una prueba simple que verifique que todo esté configurado correctamente. Por ejemplo, puede tener una página de prueba que muestre los parámetros de configuración y realice algunas pruebas básicas, como intentar conectarse a bases de datos o servidores remotos.
Aquí hay algunas prácticas posibles que he usado o encontrado. La combinación de estos generalmente se necesita en la práctica.
Sustituir los valores variables en archivos conffiles cuando se construye
Aquí hay un ejemplo de cómo se puede hacer esto con Apache Ant. Las propiedades Ant ( ${var.name}
) se pueden controlar con los archivos de configuración de compilación:
<filterset id="variables.to.replace">
<filter token="APPNAME" value="${app.name}"/>
<filter token="WEBAPP-PATH" value="${webapp.path}"/>
<filter token="ENCRYPT-ALGORITHM" value="${encrypt.algorithm}"/>
<filter token="ERROR-MAILTO" value="${error.mailTo}"/>
<!--...-->
</filterset>
<!-- Then, when building & copying the conf, replace the variables: -->
<copy todir="${properties.target.dir}">
<!-- env specific conf files -->
<fileset dir="${basedir}/env/${run.env}/webapp/WEB-INF/classes" />
<filterset refid="variables.to.replace"/>
</copy>
Lo bueno es que tienes un control fino sobre las diferentes configuraciones en el momento de compilación. Lo que es malo es que el sistema tiende a volverse muy complejo y difícil de mantener si usa este método extensivamente para un gran número de configuraciones diferentes. Además, tener que compilar los conffiles también significa ciclos de desarrollo más lentos.
Sustituir las variables de conf dentro de war en el inicio de webapp
Esto es lo que suelo hacer cuando uso Spring Framework, incluso si solo hay una configuración posible, obteniendo los beneficios de la separación de las preocupaciones. Con Spring, puede hacer que los valores conf se reemplacen con PlaceholderPropertyConfigurer dentro del contexto Spring en el inicio de la aplicación web. En este caso, debe elegir la configuración correcta, que se puede configurar, por ejemplo, en el tiempo de compilación.
En comparación con el reemplazo del tiempo de compilación, es más fácil manipular temporalmente los valores en una aplicación web no comprimida, si es necesario. Por supuesto, la aplicación web necesita reiniciarse si cambia algo, y los cambios manuales no persistirán en las redistribuciones de la aplicación de la webapp. Spring también se limita al contexto de Spring, por lo que no funciona, por ejemplo, en web.xml (pero tener variables en web.xml probablemente se debería evitar de todos modos debido a sus limitaciones).
Lectura de la conf local de un archivo predefinido
Este enfoque es probablemente el más fácil de configurar: simplemente invente una ruta de archivo de configuración, por ejemplo $HOME/mywebapp/conf.properties
y haga que su aplicación web de alguna manera la lea al inicio.
Lo bueno aquí es que no tiene que preocuparse por la conf al construir / desplegar la aplicación web. De todos modos, debe tener algunos valores predeterminados de configuración razonables que luego pueden ser anulados por el conf local.
Tener el conf en una base de datos
Esta es la solución más flexible para anular los parámetros conf, pero también puede complicarse en algunos casos. Tener el conf en una tabla con columnas de name
y value
debería funcionar para la mayoría de los casos.
Por supuesto, no puede configurar las URL de conexión JDBC en una tabla de base de datos, pero esta es una buena solución para conf simple textual / numical que afecta la operación de la aplicación web después de que se haya configurado la conexión db. Para evitar una penalización de rendimiento, asegúrese de guardar en caché la conf de alguna manera si se accederá con frecuencia.
Prácticas adicionales
Como señaló kgiannakakis, también ayuda a configurar una página de diagnóstico de configuración de algún tipo para su aplicación.
El buen ejemplo de lo que quieres se usa en Seam o Grails (prestado de Rails). Hay perfiles, por defecto tres: prod, dev, test, pero puede definir más si lo desea.
En el proyecto Seam, la compilación se realiza mediante archivos Ant. Cada archivo que los contenidos pueden variar se define para cada perfil, por ejemplo, origen de datos, scripts sql o archivos de propiedades.
import-dev.sql
import-prod.sql
import-test.sql
Cuando el archivo ant se ejecuta con el perfil elegido, se toma el archivo apropiado y el nombre del perfil se trunca desde ese nombre de archivo.
A continuación se muestra un fragmento de código que puedes colocar en tus objetivos
<copy tofile="${war.dir}/WEB-INF/classes/import.sql"
file="${basedir}/resources/import-${profile}.sql"/>
URL de JDBC, los nombres de los controladores se pueden externalizar a los archivos de propiedades (por supuesto, con nombres de perfil como sufijos)
<filterset id="persistence">
<filter token="transactionManagerLookupClass" value="${transactionManagerLookupClass}"/>
<copy tofile="${war.dir}/WEB-INF/classes/META-INF/persistence.xml"
file="${basedir}/resources/META-INF/persistence-${profile}.xml">
<filterset refid="persistence"/>
</copy>
o valores de las propiedades que puede pasar a la llamada de compilación de ant desde la línea de comandos. Este es un breve ejemplo de lo que está en Seam hecho.
Otra opción es utilizar Maven . De la misma manera, puede hacerlo por propiedades y por profiles , pero también puede usar módulos separados para dividir la configuración y crear otros módulos con la funcionalidad principal. Ejemplos típicos de casos de uso de propiedades y perfiles maven se ejecutan para la configuración de múltiples bases de datos, servidores de implementación, etc. Es aún más difícil cuando se desea crear configuraciones para diferentes proveedores, pero para Maven eso no es un problema :)
Un gran ejemplo del uso de perfiles de maven es este post del blog Carlos Sanchez .
En resumen, recomiendo encarecidamente buscar Ant / Seam y una parametrización Maven (perfiles). Esas soluciones tienen otra ventaja: la secuencia de comandos ant o maven se puede ejecutar en el servidor de CI (como Hudson ) y permite ejecutar / probar simultáneamente todos sus perfiles.
Esto dependerá en gran medida de las opciones que le brinden los servidores de aplicaciones web. Tenemos varios entornos para JBoss con diferentes URL JDBC, el nombre JNDI sigue siendo el mismo en todos los servidores, solo cambia la configuración en la instancia local, por lo que nada va mal de una generación a otra.
Supongo que la respuesta corta es que la mejor práctica es externalizar las configuraciones y mantener un buen archivo en su lugar con las configuraciones correctas para cada servidor, y que la aplicación web lea esa configuración. La naturaleza exacta de la externalización y la lectura dependerá de la configuración específica y del servidor de aplicaciones.
EDITAR: Estas configuraciones no existen como parte de la guerra (por ejemplo, en nuestro caso) de esa manera no se sobrescriben.
Hay algunas formas posibles de abordar esto:
use archivos de propiedades como usted, pero agregue un archivo de "meta-propiedades" que se utiliza para seleccionar el archivo de propiedades utilizado al definir un mapa entre un valor de entorno (por ejemplo, nombre de host de host local) en el nombre de archivo de propiedad para cargar.
coloque sus propiedades en una base de datos y defina la conexión de la base de datos a las tablas de propiedades en su servidor de aplicaciones como recurso recogido por su aplicación web.
no coloque los archivos de propiedad en su .war o .ear, sino que cree un archivo properties-deployhost.jar que contenga los archivos de propiedades por cada host de destino. enlazar el archivo .jar apropiado a la aplicación web implementada agregándolo a la ruta de la clase (por ejemplo, a través de bibliotecas compartidas en la configuración del servidor de aplicaciones por aplicación web).
Solo el primero de ellos no necesita pasos manuales adicionales cuando se implementa a expensas de tener que actualizar su fuente de configuración y crear nuevos archivos de implementación cuando se renombra el sistema de destino.
Estoy seguro de que son posibles muchas variaciones sobre estos y su enfoque; cuál es la mejor opción depende de su situación.
Lo que hacemos funciona bastante bien.
Al inicio, nuestros programas leen un archivo de configuración en una ruta codificada. Digamos que es:
/config/fun_prog/config.xml
Cada programa tiene una ruta diferente codificada (FunProgram está en fun_prog, Super Server está en sup_serv, lo que sea), por lo que no tenemos que preocuparnos de que se crucen.
Los archivos XML son leídos por una pequeña biblioteca de configuración que creamos. El archivo XML contiene la información de conexión de DB, generalmente los datos de configuración del servidor de correo, las direcciones de correo electrónico para enviar notificaciones, si debe operar en modo de prueba, las URL de los servicios externos, etc.
Entonces, cuando necesitamos hacer cambios, copiamos el archivo de configuración, editamos lo que queremos y reiniciamos el programa. Como tenemos una configuración de servidor estándar, cualquier programa se puede implementar en cualquier servidor simplemente copiando estos archivos (y el retoque httpd.conf necesario).
No es elegante, pero funciona muy bien. Es extremadamente simple de entender, agrega nuevas opciones de configuración, copia de seguridad y edición. Funciona en todas las plataformas (Unix es obvio, Windows traduce rutas que comienzan con / en c: / para que funcione sin modificaciones también).
Nuestras estaciones de trabajo básicamente ejecutan el mismo software que el servidor, solo con algunos cambios en ese archivo de configuración.
Me sorprende que nadie haya citado la API de configuración de Jakarta Commons ( http://commons.apache.org/configuration/ ) para responder a esta pregunta. Le permite tener una jerarquía de archivos (u otras fuentes de configuración como XML, JNDI, JDBC, etc.). Eso es de lo que Jeremy Seghi estaba hablando y te da una buena manera de tener tanto valores predeterminados como anulaciones locales también.
La mejor parte es que es una solución de trabajo probada, por lo que no tiene que crear algo usted mismo.
Por favor, eche un vistazo a esta URL: http://issues.apache.org/jira/browse/CONFIGURATION-394
El marco de configuración que estamos buscando es algo sobre la configuración de Apache Commons y debe admitir problemas de simultaneidad, problemas de JMX y la mayoría de las tiendas (por ejemplo, archivo .properties, archivos .xml o PreferencesAPI).
Lo que el equipo weblogic proporciona en ''Consola de administración'' es interesante, ya que a través de él puede tener actualizaciones transaccionales (atómicas) en las configuraciones para que se notifique a los oyentes registrados.
¡Los chicos Apache insisten en que este proyecto está fuera de alcance de la Configuración de los Comunes, tal vez!
He adjuntado un marco de configuración simple, mira por favor.
Puede usar el Patrón de configuración de componentes en el idioma de su elección
Se describe en los libros POSA (creo que en el cuarto volumen)
(en java puede usar el componente de commons-configuration ).
Tiendo a trabajar más con .NET últimamente, por lo que mi Java está bastante oxidado. Estoy bastante seguro de que esto funcionaría en cualquier idioma con un pequeño ajuste.
Usamos una extensión del sistema de configuración .NET que nos permite usar configuraciones específicas del entorno y / o la aplicación junto con una configuración más global. El sistema de configuración usa una configuración global para que cada máquina lo identifique como dev, beta o producción (el valor predeterminado). Un conjunto de archivos cargados en orden y la configuración del último archivo anula cualquier configuración definida en un archivo previamente cargado. Los archivos se cargan en el siguiente orden:
- Ajustes globales
- Configuración específica de la aplicación
- Anulaciones del entorno específico de la aplicación
Todos los archivos están en control de fuente, y dado que el entorno está definido en la máquina, la aplicación se está ejecutando; dado que no accederá a la configuración "beta" a menos que la configuración de la máquina lo identifique como "beta", podemos promocionar todos los archivos de configuración sin temor a apuntar inadvertidamente nuestra aplicación de producción a una base de datos de desarrollo.