1. Introducción
En el siguiente post veremos un nuevo servidor de Spring Cloud, el Servidor de Configuración!. En la entrada Spring Boot – Property analizamos como inyectar las propiedades definidas en el fichero application.yml, que se debía encontrar en la raiz de nuestro classpath, en nuestros beans de Spring.
Sin embargo esta solución no es la más mantenible ya que un cambio de properties obligaba a realizar un build y un despliegue.
Para solucionar este problema la gente de Netflix OSS ha creado el Server Configuration
!. Se encargará de obtener los ficheros de propiedades de un repositorio git para proveerlo a los distintos microservicios de nuestro sistema.
Os podéis descargar el código de ejemplo de mi GitHub aquí.
Tecnologías empleadas:
- Java 8
- Gradle 3.1
- SpringBoot 1.5.2.RELEASE
- SpringCloud 1.1.5.RELEASE
- Spring 4.3.7.RELEASE
2. Eureka server
Necesitaremos Eureka para poder realizar el registro y descubrimiento de servicios. Recordar que simplemente basta con utilizar la anotación @EnableEurekaServer
.
group 'com.jorgehernandezramirez.spring.springboot' version '1.0-SNAPSHOT' buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'spring-boot' dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR6' } } sourceCompatibility = 1.8 springBoot { mainClass = "com.jorgehernandezramirez.spring.springcloud.eureka.Application" } repositories { mavenCentral() } dependencies { compile 'org.springframework.cloud:spring-cloud-starter-eureka-server' }
package com.jorgehernandezramirez.spring.springcloud.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class Application { public Application(){ //For Spring } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
3. Configuration Server
Añadimos la dependencia org.springframework.cloud:spring-cloud-config-server
group 'com.jorgehernandezramirez.spring.springboot' version '1.0-SNAPSHOT' buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'spring-boot' dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR6' } } sourceCompatibility = 1.8 springBoot { mainClass = "com.jorgehernandezramirez.spring.springcloud.eureka.Application" } repositories { mavenCentral() } dependencies { compile 'org.springframework.cloud:spring-cloud-config-server' compile 'org.springframework.cloud:spring-cloud-starter-eureka' }
Utilizamos la anotación @EnableConfigServer
para arrancar nuestro servidor de configuración. Como queremos que se registre en Eureka añadimos la anotación @EnableDiscoveryClient
package com.jorgehernandezramirez.spring.springcloud.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer @EnableDiscoveryClient @SpringBootApplication public class Application { public Application(){ //For Spring } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Añadimos la configuración para que obtenga los properties de un repositorio de git. Esto se define en el fichero bootstrap.yml. Por otra parte el nombre con el que nuestro microservicio se registrará en eureka será configuration
spring: application: name: configuration cloud: config: server: git: uri: https://github.com/JorgeHernandezRamirez/ConfigurationFiles
En el repositorio ConfigurationFiles de nuestro git definimos los siguientes ficheros
Por otro lado en application.yml definimos el puerto en el que queremos arrancar así como la conexión con eureka.
server: port: 8889 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: hostname: localhost nonSecurePort: 8889 management: security: enabled: false
4. Backend
Nos creamos un microservicio de prueba que llamaremos backend y que deberá obtener las propiedades del servidor de configuración. Para ello tenenemos que:
- Configurar conexión con Eureka
- Configurar conexión con el Server Configuration
- Exponer controlador de test que nos devuelva la propiedad variable definida en los ficheros de propiedades de nuestro repo de git
Utilizamos las dependencias spring-cloud-starter-eureka
y spring-cloud-starter-config
para realizar la conexión con Eureka y con el Configuration Server
group 'com.jorgehernandezramirez.spring.springboot' version '1.0-SNAPSHOT' buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.2.RELEASE") } } apply plugin: 'java' apply plugin: 'idea' apply plugin: 'maven' apply plugin: 'spring-boot' dependencyManagement { imports { mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR2' } } sourceCompatibility = 1.8 springBoot { mainClass = "com.jorgehernandezramirez.spring.springcloud.backend.Application" } repositories { mavenCentral() } dependencies { compile 'org.springframework.cloud:spring-cloud-starter-eureka' compile 'org.springframework.cloud:spring-cloud-starter-config' }
Arrancamos SpringBoot a través del siguiente main.
package com.jorgehernandezramirez.spring.springcloud.backend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class Application { public Application(){ //For Spring } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Configuramos la conexión con el servidor de configuración. El descubrimiento lo haremos a través de Eureka indicando que queremos obtener el host y puerto del microservicio cuyo nombre es CONFIGURATION.
spring: application: name: backend cloud: config: discovery: service-id: CONFIGURATION enabled: true fail-fast: true
Configuramos la conexión con eureka
server: port: 8080 eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ instance: hostname: localhost nonSecurePort: 8080
Creamos un controlador de pruebas donde inyectar la propiedad variable que nos proporcionará el servidor de Configuración.
package com.jorgehernandezramirez.spring.springcloud.backend.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class TestController { @Value("${variable}") private String variableFromConfigServer; public TestController(){ //For Spring } @RequestMapping(method = RequestMethod.GET) public String getVariableFromConfigServer() { return variableFromConfigServer; } }
Llegado a este punto puedes estar preguntándote por qué para el microservicio de backend hemos llegado a definir hasta 3 ficheros de propiedades. El backend-dev.yml y backend.yml que se encuentran en nuestro repo de Git y el application.yml que se encuentra en la raiz de nuestro classpath. La respuesta es que las propiedades se obtienen de todos ellos!. A continuación se muestran los ficheros de propiedades que se consideran así como su preferencia por orden.
- backend-[PERFIL].yml (REPO GIT)
- application-[PEFIL].yml (REPO GIT)
- backend.yml (REPO GIT)
- application.yml (REPO GIT)
- application-[PERFIL].yml (CLASSPATH)
- application.yml (CLASSPATH)
PD:backend es el nombre del microservicio que se está considerando. Recordar que se define en el fichero bootstrap.yml que se debe encontrar en el classpath de la aplicación
5. Testeando nuestra aplicación
Compilamos los 3 módulos
Arrancamos los 3 microservicios
Atacamos al controlador /test
Resultado
valor
Arrancando backend con el perfil dev
Atacamos al controlador /test
Resultado
valor-desarrollo