Enmilocalfunciona

Thoughts, stories and ideas.

Arquitectura de microservicios - Parte 2: Implementación

Publicado por Daniel Sánchez el

MicroserviciosSpring BootSpring CloudSwagger

En esta segunda parte de la serie de microservicios vamos a implementar de forma rápida, sencilla y para toda la familia un microservicio basado en las siguientes tecnologías:

  • Spring Boot: como framework de aplicación.
  • Spring MVC: como framework web.
  • Spring Cloud: para integrar nuestro servicio con otros componentes que veremos más adelante.
  • Swagger: para documentar y definir nuestro API.

La idea será partir de un código funcional muy sencillo e ir integrando más diversión progresivamente.

Comencemos

Vamos a implementar un microservicio llamado Sadr que expondrá la operación ping que devuelve un mensaje.
Utilizaremos Maven para su construcción, así en su pom tendremos como parent:

<parent>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
</parent>  

Vamos a incluir en el dependency management las dependencias de Spring Cloud para posteriormente integrar nuestro servicio con un servidor de configuración y un servicio de discovery (recordemos el anterior post).

<dependencyManagement>  
    <dependencies>
        <dependency>
    <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>  

También vamos a tunearlo un poco haciendo que corra bajo Undertow embebido en lugar de Tomcat. Conseguiremos de esta manera mejorar su rendimiento. Para ello tenemos que añadir la siguiente dependencia:

<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>  

Y añadiremos también la dependencia de Spring Boot Actuator lo que nos permitirá monitorizar aspectos como salud y configuración de nuestra aplicación:

<dependency>  
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>  

A continuación vamos a ver la implementación y la configuración de nuestro servicio. Todo el código puede descargarse desde el repositorio cygnus

Implementación

Como aplicación Spring Boot tendremos una clase main que anotaremos con @SpringBootApplication. Recordemos que con esta anotación ya no son necesarias @Config y @Autoconfiguration

  • Application.java
@SpringBootApplication
public class Application {

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

Añadiremos un controlador de Spring MVC que anotaremos con las anotaciones de Swagger para definir nuestro API:

  • SadrController.java
@Api
@RestController
@RequestMapping("sadr/")
public class SadrController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @RequestMapping(method = RequestMethod.POST, value = "ping/")
    @ApiOperation(value = "ping", nickname = "ping", response = PingResponse.class)
    @ApiResponses(value = { @ApiResponse(code = 200, message = "Success", response = String.class),
            @ApiResponse(code = 201, message = "Created"), @ApiResponse(code = 400, message = "Bad Request"),
            @ApiResponse(code = 401, message = "Unauthorized"), @ApiResponse(code = 403, message = "Forbidden"),
            @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Failure") })
    public PingResponse ping(
            @ApiParam(value = "request", required = true) @RequestBody(required = true) PingRequest request) {

        logger.debug("--> ping received");
        logger.debug("--> id: {}", request.getId());
        logger.debug("--> content: {}", request.getMessage());

        return new PingResponse("Hello from Sadr - " + request.getId() + " - " + request.getMessage());
    }
}

Aprovechamos e incluimos las dependencias de Swagger. Hemos utilizado las librerías de Springfox ya que integra muy bien Swagger con Spring MVC:

<dependency>  
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.4.0</version>
</dependency>  
<dependency>  
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.4.0</version>
</dependency>  

Añadimos una clase de configuración para Swagger:

  • SwaggerConfig.java
@Configuration
@EnableSwagger2
class SwaggerConfig {

    /**
     * Create Swagger Api configuration
     *
     * @return Swagger Docket
     */
    @Bean
    public Docket sadrApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("cygnus")
                .apiInfo(apiInfo())
                .select()
                    .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                    .paths(PathSelectors.any())
                    .build()
                .pathMapping("/")
                .genericModelSubstitutes(ResponseEntity.class)
                .useDefaultResponseMessages(false);
    }

    /**
     * Generate Api Info
     *
     * @return Swagger API Info
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Sadr")
                .description("Gamma Cygni")
                .version("0.1-SNAPSHOT")
                .termsOfServiceUrl("https://es.wikipedia.org/wiki/Sadr")
                .license("Open source licensing")
                .licenseUrl("https://help.github.com/articles/open-source-licensing/")
                .build();
    }
}

Hubiera sido interesante (a la par que elegante) el poder desacoplar las anotaciones de Swagger del controlador por ejemplo en una interface, de esta manera quedaría más limpio el código del controlador, pero hasta la fecha, Swagger no lo soporta.

Configuración

Tendremos el siguiente fichero de configuración:

  • application.properties:
# HTTP Server
server:  
  port: 3333   # HTTP port

# Spring properties
spring:  
  application:
    name: sadr-service

logging:  
  file: logs/${spring.application.name}.log
  level:
    org.springframework.cloud: 'DEBUG'
    com.atsistemas: 'DEBUG'

La property server.port indica el puerto donde el servicio escuchará y spring.application.name el nombre de la aplicación.

Con esto ya tenemos listo nuestro microservicio. Para arrancarlo:
mvn spring-boot:run

Podemos probarlo mediante la interface de swagger-ui:
http://localhost:3333/swagger-ui.html

Esto todo por el momento, en el siguiente post veremos cómo hacer que nuestro microservicio cargue su configuración en tiempo de bootstrap de un servidor mediante Spring Cloud Config y se registre en un Registry Server (Eureka).

¡Síguenos en Twitter para no perderte ni un post de la serie!