1. Introducción
Hola a todos y bienvenidos de nuevo post de nuestro blog!. En esta ocasión hablaremos de Consul como sustituto de Eureka y del servidor de configuración. Y es que Consul nos permitirá, entre otras cosas, llevar a cabo el registro y descubrimiento de servicios. Además tiene la capacidad de almacenar pares clave/valor que podrán ser recuperados desde nuestras aplicaciones. Este post es análogo al que publicamos hace unos meses sobre Eureka + Ribbon + Feign, pero en lugar de utilizar Eureka utilizando Consul. Así que si no te lo has leído te invito a que le eches un vistazo antes de empezar con este.
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
- Spring 4.3.7.RELEASE
- SpringCloud 1.1.5.RELEASE
- Consul 0.9.2
2. Consul
Como ya hemos comentado Consul es un tecnología que nos permite llevar a cabo el registro y el descubrimiento de nuestros servicios así como la persistencia y recuperación de las propiedades de nuestra aplicación. Utilizaremos docker para desplegar una instancia de Consul como viene siendo habitual en nuestro blog.
Se muestra el fichero docker-compose.yml que nos permitirá correr un contenedor docker de Consul
Para arrancar nuestro contenedor basta con
Accedemos a http://localhost:8500 y podemos ver la administración de Consul!

Propiedades Key/Value
Una de las características interesantes de Consul es su capacidad para persistir y devolver propiedades comportándose como servidor de configuración. Para dar de alta dichas propiedades basta con acceder a la sección KEY/VALUE y empezar a crear nuestras propiedades.

3. Ficheros de configuración
Hacemos uso de las dependencias spring-cloud-starter-consul-all y spring-cloud-starter-feign dentro de nuestro build.gradle
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.Application"
}
repositories {
mavenCentral()
}
dependencies {
compile 'org.springframework.cloud:spring-cloud-starter-consul-all'
compile 'org.springframework.cloud:spring-cloud-starter-feign'
}
En el fichero application.yml establecemos el host y puerto de Consul. Además establecemos cómo queremos que nuestro microservicio se registre. Es importante destacar que hay que indicarle a Consul a través de la propiedad spring.cloud.consul.discovery.healthCheckPath la url de chequeo del estado de la aplicación.
server:
port: 8080
spring:
cloud:
consul:
host: localhost
port: 8500
discovery:
port: 8080
prefer-ip-address: true
healthCheckPath: /health
healthCheckInterval: 5s
En el fichero bootstrap.yml indicamos el nombre de la aplicación y el formato de propiedades que esperamos que Consul nos devuelva. En nuestro caso indicamos el formato YAML.
Por defecto SpringBoot irá a buscar las propiedades en las siguientes rutas (se muestran por prioridad)
- /config/[NOMBRE_MICROSERVICIO],[PERFIL]
- /config/[NOMBRE_MICROSERVICIO]
- /config/application,[PERFIL]
- /config/application
Sin embargo, si lo que queremos es definir un yaml dentro de Consul en lugar de tener que dar de alta una a una las propiedades de nuestra aplicación deberemos definir dentro de bootstrap.yml la propiedad spring.clolud.consul.config.format con el valor YAML tal y como se ha mostrado anteriormente. En este caso dichos yaml se deben crear en alguna de las siguientes rutas dentro de consul (se muestran por prioridad)
- /config/[NOMBRE_MICROSERVICIO],[PERFIL]/data
- /config/[NOMBRE_MICROSERVICIO]/data
- /config/application,[PERFIL]/data
- /config/application/data
En nuestro caso definiremos nuestro YAML dentro de la ruta /config/application/data

4. Ficheros Java
Se muestra el main de la aplicación.
package com.jorgehernandezramirez.spring.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.jorgehernandezramirez.spring.springcloud.feign")
public class Application {
public Application(){
//For Spring
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Para hacer uso de Ribbon y Feign es necesario definir dentro del contexto de Spring un objeto de la clase RestTemplate haciendo uso de la anotación @LoadBalanced para indicar que se va a hacer uso del descubrimiento de servicios.
package com.jorgehernandezramirez.spring.springcloud.configuration;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfiguration {
@Bean
@LoadBalanced
RestTemplate loadBalancedRestTemplate() {
return new RestTemplate();
}
}
Mostramos la clase TestFeign que nos permitirá invocar a nuestras Apis a través de Feign.
package com.jorgehernandezramirez.spring.springcloud.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient("springcloudwebtest")
public interface TestFeign {
@RequestMapping(value="/ping", method = RequestMethod.GET)
String doAlive();
}
Mostramos la clase de test que permitirá invocar a las Apis haciendo uso de Ribbon y Feign apoyándose en Consul
package com.jorgehernandezramirez.spring.springcloud.controller;
import com.jorgehernandezramirez.spring.springcloud.feign.TestFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/ping")
public class TestController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private TestFeign testFeign;
public TestController(){
//For Spring
}
@RequestMapping
public String doAlive() {
return "Alive!";
}
@RequestMapping("/rest")
public String doRestAlive() {
return new RestTemplate().getForObject("http://localhost:8080/ping", String.class);
}
@RequestMapping("/rest/ribbon")
public String doRestAliveUsingEurekaAndRibbon() {
return restTemplate.getForObject("http://springcloudwebtest/ping", String.class);
}
@RequestMapping("/rest/feign")
public String doRestAliveUsingFeign() {
return testFeign.doAlive();
}
}
Se muestra la clase PropertyController en donde se inyectará la propiedad property, que debe estar definida dentro de Consul, para exponer su valor a través de un controlador.
package com.jorgehernandezramirez.spring.springcloud.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/property")
public class PropertyController {
@Value("${property}")
private String property;
public PropertyController(){
//For Spring
}
@RequestMapping
public String getProperty() {
return property;
}
}
5. Probando la aplicación
A continuación compilamos nuestros fuentes y arrancamos.
Compilamos
Arrancamos la aplicación
Para probar que desde RestTemplate se está haciendo uso del descubrimiento de servicios utilizando Consul, atacamos a la url http://localhost:8080/rest/ping/ribbon obteniendo
Alive!
Por otro lado para probar que Feign está haciendo uso del descubrimiento de servicios utilizando Consul, atacamos a la url http://localhost:8080/rest/ping/feign obteniendo
Alive!
Por último comprobamos que la propiedad definida dentro de Consul se ha inyectado correctamente. Para ello atacamos a la url http://localhost:8080/property obteniendo
property value