Esto es algo que mucha, veces no le damos mucha importancia, pero que al largo plazo nos simplifica mucho la vida y si lo tenemos claro no es muy difícil de implementar.
El proyecto de ejemplo lo puede consultar en la siguiente url https://github.com/blancoparis-tfc/SpringProfile
Antes de nada vamos a ver los diferentes tipos de entornos que podemos tener en un proyecto.
- Desarrollo: Es el entorno con las configuraciones para el desarrollo.
- Integración: Es el entorno donde vamos a subir todos los programadores los cambios, para poder ver si chocan, y realizar las diferentes pruebas,
- PreProduccion: Es un entorno equivalente al de produccion, para probar los cambios sin ir a producción.
- Producción: Es el entorno de producción.
Esta historia se puede plantear de dos maneras:
- Una construcción independiente por cada entorno, delegando la responsabilidad a la herramienta de build (Maven, gradle), con sus diferentes profile por cada entorno.
- Una misma construcción que a partir de una variable de entorno establece que entorno y configuraciones vamos a trabajar.
Las dos opciones son factibles, a mi personalmente me gusta la segunda opción. Que ademas nos proporciona las siguientes ventajas:
- La responsabilidad del entorno la delegamos al servidor, y por lo cual un administrador de sistema puede realizar cambios sin necesidad de depender del equipo de desarrollo (En algunas cosas), seguridad, B.D etc...
- Un desarrollador cambiando la configuración de su IDE, puede estar trabajando sobre producción (Si fuera necesario).
- Podemos llevar el war de desarrollo directamente a producción, sin tener que realizar un montaje. Esto en algún caso de emergencia nos ahorraría algo de tiempo.
- Quita la responsabilidad de las configuraciones en la herramienta de build, simplificando su trabajo.
Desventajas:
- Requiere, de unas configuraciones algo mas complejas y un nivel de abstracción mayor.
- Es necesario que el framework nos de herramientas que nos facilite esta gestión.
Una vez expuesto, que es un entorno para mi y de que manera vamos a resolver el problema, vamos a ver con que herramientas contamos en Spring:
En el caso de spring , nos proporciona el concepto de profile, que nos permite tener uno o varios. Aquí se nos plantea otro dilema como vamos a utilizarlo.
- Un solo profile: Aquí tendríamos un solo profile activo, y un profile por cada entorno al cual vincularemos la configuración.
- Varios profile: Aquí tendríamos varios profile activos y en cada entorno tendríamos que ir poniendo los profile que nos interesen.
En la documentación de spring nos ponen un ejemplo con un profile activo para desarrollo y otro para producción.
Un solo profile activo
El profile activo, se refiere al entorno en cuestión (dev, prod, preProd,int). Aquí la filosofía, es que hacemos una configuración a medida para el entorno. Esto es una buena opción en un proyecto empresarial o a medida en el cual tengamos 3 o 4 configuraciones idénticas. Normalmente la norma es poner una configuración por defecto y el entorno nos active las excepciones.
Si tenemos 3 o 4 entornos nos simplifica la configuración del servidor, ya que solo tenemos que mapear el profile con el entorno.
Esta solución no es la mejor si vamos a tener múltiples entornos de producción y queremos que nuestra herramienta, sea muy adaptable y que la configuración fuera del código.Varios profile activos
Aquí, tendremos varios profiles activos, cada uno se refería a un aspecto de configuración, por ejemplo en el caso de la seguridad en spring podemos tener 3 tipos diferentes:
- SeguridadMemoria: Mock en memoria (Usuarios puesto a fuego), se suele utilizar en el entorno de desarrollo.
- SeguridadLadp: Ldap, se validan los usuarios contra un directorio activo. + Configuración del ldap en cuestión en un fichero externo.
- SeguridadBD: Los usuarios se valida contra la B.D. + Esquema de B.D.
En este ejemplo, en el entorno de desarrollo y integración podemos tener los usuarios de palo, ya que no tenemos la necesidad de ir contra el directorio activo y saber las contraseñas de usuarios. Y en preproducción y producción dependiendo del entorno iremos contra un directorio activo o la B.D.
Y esta operación la podríamos realizar por cada aspecto de la configuración que lo precisara.
Como podemos ver esta configuración le da mas libertad al administrador en el servidor para activar las diferentes configuraciones. En cada entorno, Pero también complica esa configuración.
Esto tiene sentido si tenemos muchos entornos diferentes al que llevar nuestra aplicación.
Conclusión:
Con que configuración nos vamos a quedar, pues en este caso dependiendo de nuestras circunstancias, como aquí estamos planteando como realizar una separación de un proyecto en 4 entornos de trabajo, nos sale mas a cuenta la primera opción.
Profile
Ahora que ya tenemos claro que vamos a configurar 4 entorno de trabajo, con una misma construcción y que vamos a trabajar con un solo entorno activo, vamos a ver que herramientas nos proporciona spring, para facilitarnos la tarea. Desde la versión 3 de spring mas o menos permite utilizar el concepto de profile.
Una vez hemos visto algunas formas, como podemos plantear en nuestro proyecto la activación de un profile, esto es un poco a gusto del consumidor y de las necesidades del proyecto. Yo por ejemplo me gusta que siempre haya una configuración por defecto activa, si no configuro nada y claro esta en su defecto para evitar desgracias mayores siempre es el entorno de desarrollo (Sobra explicar por que no poner producción por defecto xd).
Profile: Es un grupo lógico de las definiciones de configuración que se activan y beans.En los ejemplo de la documentación oficial de spring, nos ponen un ejemplo de dev(desarrollo) y prod (Producción). Mas o menos tenemos que saber 2 cosas de los profile en spring:
- Como se activa, ya que por defecto no tiene ninguno.
- Como indicas a una configuración o beans de spring que esta asociado a un profile.
¿Como se activa un profile?
Aquí tenemos diferentes maneras, que utilizaremos según nuestras necesidades,
- Programáticamente a través del WebApllicationInitializer
@Configuration public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { servletContext.setInitParameter("spring.profiles.active", "dev"); } }
- Programáticamente a través de ConfigurableEnviroment.
@Autowired private ConfigurableEnvironment env; ... env.setActiveProfiles("someProfile");
- Parametro de contexto en web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-config.xml</param-value> </context-param> <context-param> <param-name>spring.profiles.active</param-name> <param-value>dev</param-value> </context-param>
- JVM parámetro del sistema
-Dspring.profiles.active=dev
- Variable de entorno.
export spring_profiles_active=dev
El tema de activación lo he sacado del siguiente articulo http://www.baeldung.com/spring-profiles
Como podemos conseguir ese comportamiento que hemos explicado en el párrafo anterior, pues muy fácil, utilizaremos por un lado la configuración programáticamente del WebAplicationInitializer, que seguirá el siguiente algoritmo, si no tenemos activo ningún profile, activa pragmáticamente "dev". Y para activar el entorno que nos interesa usaremos la configuración de JVM parámetro del sistema esto nos permite que la elección del entorno estar fuera de nuestro código y podremos configurar-lo en el servidor web, que lo contendrá y de esta manera tendremos el mismo paquete para cualquier entorno.
package org.dbp.conf; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.commons.lang3.StringUtils; import org.dbp.conf.profiles.ProfilesAplication; import org.springframework.context.annotation.Configuration; import org.springframework.web.WebApplicationInitializer; @Configuration public class MiWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { String entornoActivo=System.getProperty("spring.profiles.active"); if(StringUtils.isBlank(entornoActivo)){ entornoActivo=ProfilesAplication.dev; } servletContext.setInitParameter("spring.profiles.active",entornoActivo); } }
¿Como indicar que configuración se asocia a un profile?
Esto es fácil, solo tenemos que utilizar, la anotación @Profile("<entorno>) y esto activara la configuración o bean asociado.
Otra forma es recuperar del entorno los contextos activos y actuar en consecuencia, en nuestro ejemplo de momento vamos a definir los recursos estáticos distintos para cada contexto como ejemplo:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String entorno=env.getActiveProfiles()[0]; registry .addResourceHandler("/resources/**") .addResourceLocations("/resources/") .setCachePeriod(3600) .resourceChain(true) .addResolver(new PathResourceResolver()); registry .addResourceHandler("/env/**") .addResourceLocations("/resources/env/"+entorno+"/") .setCachePeriod(3600) .resourceChain(true) .addResolver(new PathResourceResolver()); }
Como podéis observar en este articulo, es bastante fácil de usar y nos da muchas opciones por lo cual es algo que al final tenemos que ajustar el traje a nuestras necesidades.