Geekflare recibe el apoyo de nuestra audiencia. Podemos ganar comisiones de afiliación de los enlaces de compra en este sitio.
En Desarrollo Última actualización: 25 de septiembre de 2023
Compartir en:
Escáner de seguridad de aplicaciones web Invicti - la única solución que ofrece verificación automática de vulnerabilidades con Proof-Based Scanning™.

Exploremos cómo implementar gRPC en Java

gRPC (Google Remote Procedure Call): gRPC es una arquitectura RPC de código abierto desarrollada por Google para permitir la comunicación de alta velocidad entre microservicios. gRPC permite a los desarrolladores integrar servicios escritos en diferentes lenguajes. gRPC utiliza el formato de mensajería Protobuf (Protocol Buffers), un formato de mensajería muy eficiente y de gran empaquetado para serializar datos estructurados.

Para algunos casos de uso, la API gRPC puede ser más eficiente que la API REST

Intentamos escribir un servidor en gRPC. En primer lugar, necesitamos escribir varios archivos .proto que describen servicios y modelos (DTO). Para un servidor sencillo, utilizaremos ProfileService y ProfileDescriptor

ProfileService tiene el siguiente aspecto

sintaxis = "proto3";
package com.deft.grpc;
import "google/protobuf/empty.proto";
import "profile_descriptor.proto";
service ProfileService {
 rpc GetCurrentProfile (google.protobuf.Empty) returns (ProfileDescriptor) {}
 rpc clientStream (stream ProfileDescriptor) returns (google.

protobuf.Empty) {}


 rpc serverStream (google.protobuf.Empty) devuelve (stream ProfileDescriptor) {}
 rpc biDirectionalStream (stream ProfileDescriptor) devuelve (stream ProfileDescriptor) {}

}


gRPC soporta una gran variedad de opciones de comunicación cliente-servidor. Las desglosaremos todas

  • Llamada normal al servidor - solicitud/respuesta.
  • Streaming de cliente a servidor.
  • Streaming de servidor a cliente.
  • Y, por supuesto, el flujo bidireccional.

El servicio ProfileService utiliza el ProfileDescriptor, que se especifica en la sección de importación

sintax = "proto3";
package com.deft.grpc;
message ProfileDescriptor {
 int64 profile_id = 1;
 string name = 2;

}


  • int64 es Long para Java. Pertenece al id del perfil.
  • Cadena - al igual que en Java, se trata de una cadena variable.

Puede utilizar Gradle o maven para construir el proyecto. Es más conveniente para mí utilizar maven. Y más adelante será el código utilizando maven. Esto es importante decirlo porque para Gradle, la futura generación del .proto será ligeramente diferente, y el archivo de construcción tendrá que ser configurado de manera diferente. Para escribir un simple servidor gRPC, sólo necesitamos una dependencia

<dependencia>
 <groupId>io.github.lognet</groupId>
 <artifactId>grpc-spring-boot-starter</artifactId>
 <version>4.5.4</version>
</dependencia&gt

Es simplemente increíble. Este arrancador hace una enorme cantidad de trabajo por nosotros

El proyecto que vamos a crear tendrá este aspecto

Necesitamos GrpcServerApplication para iniciar la aplicación Spring Boot. Y GrpcProfileService, que implementará métodos del servicio .proto. Para utilizar protoc y generar clases a partir de archivos .proto escritos, añada protobuf-maven-plugin a pom.xml. La sección build tendrá el siguiente aspecto

<build>
 <extensions>
 <extension>
 <groupId>kr.motd.maven</groupId>
 <artifactId>os-maven-plugin</artifactId>
 <version>1.6.2</version>
 </extension>
 </extensions>
 <plugins>
 <plugin>
 <groupId>org.xolstice.maven.plugins</groupId>
 <artifactId>protobuf-maven-plugin</artifactId>
 <version>0.6.1</version>
 <configuration>
 <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
 <outputDirectory>${basedir}/target/generated-sources/grpc-java</outputDirectory>
 <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
 <pluginId>grpc-java</pluginId>
 <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.38.0:exe:${os.detected.classifier}</pluginArtifact>
 <clearOutputDirectory>false</clearOutputDirectory>
 </configuration>
 <executions>
 <execution>
 <goals>
 <goal>compile</goal>
 <goal>compile-custom</goal>
 </goals>
 </execution>
 </executions>
 </plugin>
 </plugins>
 </build&gt
  • protoSourceRoot - especifique el directorio donde se encuentran los archivos .proto.
  • outputDirectory - seleccione el directorio donde se generarán los archivos.
  • clearOutputDirectory - una bandera que indica no borrar los archivos generados.

En este punto, ya puede construir un proyecto. A continuación, debe ir a la carpeta que hemos especificado en el directorio de salida. Los archivos generados estarán allí. Ahora puede implementar gradualmente GrpcProfileService

La declaración de la clase tendrá este aspecto

@GRpcService
public class GrpcProfileService extends ProfileServiceGrpc.ProfileServiceImplBase

Anotación GRpcService - Marque la clase como un frijol grpc-servicio

Dado que heredamos nuestro servicio de PerfilServicioGrpc, ProfileServiceImplBase, podemos anular los métodos de la clase padre. El primer método que anularemos es getCurrentProfile

   @Override
 public void getCurrentProfile(Empty request, StreamObserver<ProfileDescriptorOuterClass.ProfileDescriptor> responseObserver) {
 System.out.println("getCurrentProfile");
 responseObserver.onNext(DescriptorDePerfilOuterClass.ProfileDescriptor
.newBuilder()
.setProfileId(1)
.setName("test")
.build());
 responseObserver.onCompleted();
 }

Para responder al cliente, debe llamar al método onNext en el StreamObserver pasado. Después de enviar la respuesta, envíe una señal al cliente de que el servidor ha terminado de trabajar onCompleted. Al enviar una solicitud al servidor getCurrentProfile, la respuesta será

{
 "profile_id": "1",
 "name":

test"

}


A continuación, echemos un vistazo al flujo del servidor. Con este enfoque de mensajería, el cliente envía una petición al servidor, el servidor responde al cliente con un flujo de mensajes. Por ejemplo, envía cinco peticiones en un bucle. Cuando finaliza el envío, el servidor envía un mensaje al cliente sobre la finalización satisfactoria del flujo

El método de flujo del servidor anulado tendrá el siguiente aspecto

@Override
 public void serverStream(Solicitud vacía, StreamObserver<DescriptorDePerfilOuterClass.ProfileDescriptor> responseObserver) {
 for (int i = 0; i < 5; i ) {
 responseObserver.onNext(ProfileDescriptorOuterClass.ProfileDescriptor
.newBuilder()
.setProfileId(i)
.build());
 }
 responseObserver.onCompleted();
 }

Así, el cliente recibirá cinco mensajes con un PerfilId, igual al número de respuesta

{
 "profile_id": "0",
 "name": ""
}
{
 "profile_id": "1",
 "name": ""
}
...
{
 "profile_id": "4",
 "name":

“”


}

El flujo cliente es muy similar al flujo servidor. Sólo que ahora el cliente transmite un flujo de mensajes y el servidor los procesa. El servidor puede procesar los mensajes inmediatamente o esperar a recibir todas las peticiones del cliente y luego procesarlas.

   @Override
 public StreamObserver<ProfileDescriptorOuterClass.ProfileDescriptor> clientStream(StreamObserver<Empty> responseObserver) {
 return new StreamObserver<>() {

 @Override
 public void onNext(ProfileDescriptorOuterClass.ProfileDescriptor profileDescriptor) {
 log.info("ProfileDescriptor del cliente. Profile id: {}", profileDescriptor.getProfileId());
 }

 @Override
 public void onError(Throwable throwable) {

 }

 @Override
 public void onCompleted() {
 responseObserver.onCompleted();
 }
 };
 }

En el flujo Cliente, debe devolver al cliente el StreamObserver al que el servidor recibirá los mensajes. Se llamará al método onError si se ha producido un error en el flujo. Por ejemplo, ha terminado incorrectamente

Para implementar un flujo bidireccional, es necesario combinar la creación de un flujo desde el servidor y el cliente

@Override
 public StreamObserver<DescriptorDePerfilOuterClass.ProfileDescriptor> biDirectionalStream(
 StreamObserver<DescriptorDePerfilOuterClass.ProfileDescriptor> responseObserver) {

 return new StreamObserver<>() {
 int pointCount = 0;
 @Override
 public void onNext(ProfileDescriptorOuterClass.ProfileDescriptor profileDescriptor) {
 log.info("biDirectionalStream, pointCount {}", pointCount);
 responseObserver.onNext(ProfileDescriptorOuterClass.ProfileDescriptor
.newBuilder()
.setProfileId(pointCount )
.build());
 }

 @Override
 public void onError(Throwable throwable) {

 }

 @Override
 public void onCompleted() {
 responseObserver.onCompleted();
 }
 };
 }

En este ejemplo, en respuesta al mensaje del cliente, el servidor devolverá un perfil con una cuenta de puntos aumentada

Conclusión

Hemos cubierto las opciones básicas para la mensajería entre un cliente y un servidor utilizando gRPC: flujo servidor implementado, flujo cliente, flujo bidireccional

El artículo fue escrito por Sergey Golitsyn

  • Geekflare Editorial
    Autor
    El equipo editorial de Geekflare está formado por un grupo de escritores y editores experimentados dedicados a ofrecer contenidos de alta calidad a nuestros lectores. Nos comprometemos a ofrecer contenido práctico que ayude a crecer a particulares y empresas.
Gracias a nuestros patrocinadores
Más lecturas sobre desarrollo
Potencia tu negocio
Algunas de las herramientas y servicios que le ayudarán a hacer crecer su negocio.
  • Invicti utiliza el Proof-Based Scanning™ para verificar automáticamente las vulnerabilidades identificadas y generar resultados procesables en tan solo unas horas.
    Pruebe Invicti
  • Web scraping, proxy residencial, gestor de proxy, desbloqueador web, rastreador de motores de búsqueda, y todo lo que necesita para recopilar datos web.
    Pruebe Brightdata
  • Monday.com es un sistema operativo de trabajo todo en uno que te ayuda a gestionar proyectos, tareas, trabajo, ventas, CRM, operaciones, flujos de trabajo y mucho más.
    Prueba Monday
  • Intruder es un escáner de vulnerabilidades en línea que encuentra puntos débiles de ciberseguridad en su infraestructura, para evitar costosas violaciones de datos.
    Prueba Intruder