Anotaciones de primavera: Nube de primavera

Spring Framework es un marco muy robusto, lanzado en 2002. Sus características principales se pueden aplicar a aplicaciones simples de Java o extenderse a aplicaciones complejas y modernas...

Introducción

Spring Framework es un marco muy robusto, lanzado en 2002. Sus funciones principales se pueden aplicar a aplicaciones Java sencillas o extenderse a aplicaciones web complejas y modernas.

Como se actualiza constantemente y sigue nuevos paradigmas de arquitectura y programación, ofrece soporte para muchos otros marcos que funcionan de la mano con él.

Con una gama tan amplia de funcionalidades, es normal que nos presente algunas anotaciones nuevas, que son una parte clave del desarrollo de aplicaciones Spring.

La configuración de Spring es totalmente personalizable, lo que originalmente se hizo a través de archivos de configuración XML. Sin embargo, este enfoque se ha vuelto obsoleto y la mayoría de las personas hoy en día recurren a la configuración de anotaciones.

Dicho esto, esta serie de artículos tiene como objetivo desentrañar las opciones que tiene como desarrollador para configurar y usar Spring Framework:

Anotaciones de Spring Cloud

Nube de primavera es una gran extensión del ya robusto Spring Framework. Permite a los desarrolladores crear patrones comunes sin esfuerzo ni dolor cuando se trata de una arquitectura basada en la nube, como la configuración de disyuntores, clientes de detección, enrutamiento, etc.

Ya hemos publicado varios artículos que cubren algunos de estos temas, por lo que si desea ver estas anotaciones sobre ejemplos prácticos prácticos, estos son un gran comienzo:

@EnableConfigServer

Spring Cloud nos presenta varias herramientas útiles, cada una de las cuales necesita algún tipo de configuración.

Si estamos usando varias herramientas, sería lógico almacenar todos los detalles de configuración en un solo lugar, similar a un archivo application.properties.

Para hacer esto, anotamos una clase con la anotación @EnableConfigServer, aplicada a nivel de clase:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableConfigServer
public class SomeApplication {
    public static void main(String[] args) {
        SpringApplication.run(SomeApplication.class, args);
    }
}

Esta anotación le dice a Spring dónde buscar configuraciones y al crear una configuración de servidor centralizada como esta, otras aplicaciones pueden comunicarse con él a través de su puerto, que por defecto es 8080.

@EnableEurekaServer

Al desarrollar un proyecto con una arquitectura de microservicios, especialmente cuando hay numerosos servicios que deberían funcionar juntos, nos enfrentamos a un problema. La forma en que estos servicios se comunican entre sí.

Podríamos codificar todos los nombres y puertos en un archivo de propiedades, pero esto es una mala práctica y no es escalable en absoluto. Incluso si lo hiciéramos, ¿qué sucede cuando hay varias instancias de un servicio? ¿Cuál responde a la solicitud?

To solve these, we can rely on Descubrimiento de servicios via Eureka.

Muy similar a la anotación @EnableConfigServer, crearemos un servidor Eureka anotando una clase con @EnableEurekaServer, que ahora se puede usar para buscar otros servicios registrados y administrarlos:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableEurekaServer
public class SomeApplication {
    public static void main(String[] args) {
        SpringApplication.run(SomeApplication.class, args);
    }
}

@EnableEurekaClient

Un servidor Eureka no es nada sin sus servicios. Cada servicio que queramos poner en el radar de nuestro servidor debe anotarse con la anotación @EnableEurekaClient.

Como alternativa, podríamos usar la anotación @EnableDiscoveryClient, que proviene de spring-cloud-commons. Sin embargo, si conoce la implementación específica que utilizará, es mejor ser específico. Si está utilizando la anotación @EnableDiscoveryClient más genética, Spring elegirá la implementación en función de los .jars presentes en el classpath.

1
2
3
4
5
6
7
@SpringBootApplication
@EnableEurekaClient
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        }
}

@EnableDiscoveryClient

La anotación de cliente de detección predeterminada que marca una clase como un servicio que se debe poner en el radar para un servidor.

@EnableCircuitBreaker

Una vez más, cuando trabajamos con microservicios, nos enfrentamos a un gran problema. Es común que los servicios trabajen con otros servicios para completar ciertas solicitudes.

Digamos que el Servicio A llama al Servicio B, que depende del Servicio C para completar una solicitud. Ahora digamos que el Servicio C falla por completo debido a un error de red o una sobrecarga. Lo que sucede a continuación es un error en cascada en el flujo de lógica que regresa al Servicio A.

Lo que podemos hacer para rectificar esto es implementar disyuntores. Cada servicio debe tener un punto de ruptura de circuito, y si ocurre algo incorrecto, “abren sus circuitos” para que el problema no se traslade a otros servicios. En este caso, el disyuntor de nuestra elección aísla el servicio que falla para que otros servicios no puedan llamarlo y fallar también.

La anotación @EnableCircuitBreaker se aplica a nivel de clase, para todos y cada uno de los servicios en nuestra arquitectura de microservicios:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceA {

    public static void main(String[] args) {
        SpringApplication.run(ServiceA.class, args);
    }
}

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceB {

    public static void main(String[] args) {
        SpringApplication.run(ServiceB.class, args);
    }
}

@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ServiceC {

    public static void main(String[] args) {
        SpringApplication.run(ServiceC.class, args);
    }
}

El patrón de disyuntores en Spring se implementa a través de Nube de primavera: Hystrix.

@ComandoHystrix

Para que el patrón del disyuntor funcione completamente, no solo podemos anotar clases. Dado que en casi todas las situaciones podemos "esperar" que un método pueda ser riesgoso, en el sentido de que podría fallar cuando se lo llame, lo marcamos con @HystrixCommand. Junto con la anotación, también podemos agregar una bandera que apunte a un método diferente para ejecutar si el original falla:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@GetMapping(value = "/personalized/{id}")
@HystrixCommand(fallbackMethod = "recommendationFallback")
public Product[] personalized(@PathVariable int id) {
    Product[] result = restTemplate.getForObject("http://recommendation-service/recommendations", Product[].class);
    return result;
}

public Product[] recommendationFallback(int id) {
    System.out.println("=======recommendationFallback=========" + id);
    return new Product[0];
}

@RibbonClient

Cinta funciona como un equilibrador de carga en el lado del cliente y le brinda control sobre los clientes HTTP y TCP.

En la mayoría de los casos, al usar un cliente de detección como Eureka, no necesita usar esta anotación, ya que se aplica de manera predeterminada. En la gran mayoría de los casos, las opciones predeterminadas son lo suficientemente buenas como para encargarse del equilibrio de carga, pero si necesita modificarlas, puede hacerlo:

1
2
3
4
5
@Configuration
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class SomeConfiguration {

}

La clase CustomConfiguration también debe ser una clase anotada @Configuration con la configuración personalizada de la cinta configurada como beans.

@Carga equilibrada

La anotación @LoadBalanced se usa para marcar RestTemplates que deberían funcionar con RibbonLoadBalancerClient al interactuar con sus servicios:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@RestController
@RibbonClient(name = "custom", configuration = CustomConfiguration.class)
public class SomeApplication {

    @LoadBalanced
    @Bean
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
    // ...
}

Esta anotación básicamente permite que RestTemplate aproveche su compatibilidad integrada para equilibrar la carga.

Conclusión

El framework Spring es un framework poderoso y robusto que realmente cambió el juego cuando se trata de desarrollar aplicaciones web. Entre su gran cantidad de proyectos, el módulo Spring Cloud es una gran extensión del marco original.