Ejemplo de gRPC en Spring Boot
En una entrada anterior hablamos sobre gRPC, como un framework desarrollado por Google, que ayuda a la conectividad en un mundo políglota. Así que, hoy vamos a ver un ejemplo práctico con Grpc en Spring Boot.
Manos a la obra
Dependencias Maven
Una vez creado el esqueleto de nuestro proyecto Spring Boot, que lo podemos hacer desde su página initializr, tendremos que añadir las siguientes dependencias maven en nuestro pom.xml:
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.16.1</version> </dependency> <dependency> <groupId>org.lognet</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>0.0.6</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </exclusion> </exclusions> </dependency>
Aparte de las librerías nativas de gRPC, vamos a añadir un starter de Spring boot, que lo que va a hacer es ejecutar el servidor gRPC embebido con @GRpcService, podéis echar un ojo a su código aquí.
Para poder utilizar el starter de gRPC para spring boot, vamos a añadir el siguiente repositorio:
<repositories> <repository> <snapshots> <enabled>false</enabled> </snapshots> <id>bintray-lognet-maven</id> <name>bintray</name> <url>http://dl.bintray.com/lognet/maven</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <snapshots> <enabled>false</enabled> </snapshots> <id>bintray-lognet-maven</id> <name>bintray-plugins</name> <url>http://dl.bintray.com/lognet/maven</url> </pluginRepository> </pluginRepositories>
Definir el Servicio
Para comenzar, definimos un servicio en el que específicamos que métodos podrán ser llamados, este es el proceso en que creamos el fichero .proto en el que también se específica el cuerpo del mensaje.
Vamos a crear un servicio en nuestro fichero .proto
syntax = "proto3"; option java_multiple_files = true; package com.refactorizando.grpc.server.example; enum BookType { BOOK = 0; NEWS_PAPER = 1; COMIC_BOOK = 2; } message Book { string ISBN = 1; string title = 2; string author = 3; int32 page = 4; repeated string keyword = 5; BookType bookType = 6; } message BookList { repeated Book book = 1; } service BookService { rpc createBooks(BookList) returns (BookList); }
Este fichero será compilado y convertido a clases de Java, el fichero .proto de arriba generará la clase Book, BookList, BookType.
Creando parte servidora
Servicio
A continuación vamos a crear un servicio haciendo uso de la anotación @GRpcService, esta clase va a extender de BookServiceGrpc, que ha sido creada de manera automática, al igual que las clases Book, BookList y Booktype, en la que vamos a crear una lista de libros y devolverla en una respuesta:
@GRpcService @Slf4j public class BookGrpcService extends BookServiceGrpc.BookServiceImplBase { @Override public void createBooks(BookList request, StreamObserver<BookList> responseObserver) { log.debug("Request " + request); BookList.Builder responseBuilder = BookList.newBuilder(); BookUtil.assignISBN(request.getBookList()).forEach(responseBuilder::addBook); BookList bookListResponse = responseBuilder.build(); log.debug("Response " + bookListResponse); responseObserver.onNext(bookListResponse); responseObserver.onCompleted(); } }
Controlador
El controlador será un controlador básico de Spring en el que se hará un post y un get, el primero para añadir libros y el segundo para recuperarlos.
Creando parte cliente
En este apartado vamos a crear el servicio para el cliente, el cual hará peticiones a la parte anterior, mediante el endpoint que habremos expuesto en el controlador del servidor. Para ello, vamos a compilar primero nuestro fichero .proto, que será el mismo que en el caso anterior, y a crear el siguiente servicio:
@Service @Slf4j public class BookServiceGrpcClient { public BookList createBooks(List<Book> bookList) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565) .loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance()) .usePlaintext(true) .build(); BookServiceGrpc.BookServiceBlockingStub bookServiceBlockingStub = BookServiceGrpc.newBlockingStub(channel); BookList.Builder builder = BookList.newBuilder(); bookList.forEach(builder::addBook); BookList request = builder.build(); logger.debug("Request " + request); BookList response = bookServiceBlockingStub.createBooks(request); logger.debug("Response " + response); return response; } }
En esta clase lo que hacemos es utilizar el objeto ManagedChannel para poder realizar la comunicación con el servidor.
Conclusión
La mejor manera de entender como funciona gRPC es con un ejemplo con Spring Boot que puedes ver aquí.