Introducción
gRPC es un framework de procedimiento remoto de alto rendimiento desarrollado por Google. Utiliza el protocolo HTTP/2 para la comunicación entre los servidores y los clientes, y permite la comunicación entre los servicios de diferentes lenguajes de programación.
Configuración del entorno
Info |
---|
En el archivo |
Code Block |
---|
testImplementation 'io.grpc:grpc-testing:1.41.0' testImplementation group: 'com.google.protobuf', name: 'protobuf-java', version:'3.23.2' implementation 'io.grpc:grpc-stub:1.53.0' implementation 'io.grpc:grpc-api:1.53.0' implementation 'io.grpc:protoc-gen-grpc-java:1.53.0' implementation 'io.grpc:grpc-core:1.53.0' implementation 'io.grpc:grpc-netty-shaded:1.53.0' implementation 'com.google.api.grpc:proto-google-common-protos:2.14.1' implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'io.grpc:grpc-protobuf:1.55.1' |
Archivos .proto
En gRPC, los servicios y los mensajes que se envían entre el cliente y el servidor se definen en archivos .proto
, que utilizan el lenguaje de definición de interfaz (IDL) de Protocol Buffers. Aquí es donde se definen las operaciones que el servicio puede realizar y los tipos de datos que se envían y reciben. Esencialmente, es la especificación de la API de gRPC.
Info |
---|
Agregar los archivos |
ejemplo:
Stubs
Un "stub" en gRPC es un término utilizado para referirse al cliente de un servicio gRPC que se conecta a un servidor. Es esencialmente una pieza de código generada generado a partir del archivo .proto
que un cliente puede usar para invocar métodos de un servicio remoto. Toma un mensaje de protocolo, serializa el mensaje en el formato correcto, envía la solicitud a través de la red, y luego espera y deserializa las respuestas para enviarlas de vuelta al código de llamada.
El enfoque más común para realizar pruebas en Java con gRPC es utilizar un stub generado automáticamente. Esto permite enfocarse en probar la lógica específica del cliente sin preocuparse por la complejidad de la comunicación subyacente.
Generar los stubs (archivos Java) a partir del archivo .proto:
Gradle posee un plugin que permite generar los archivos Java, los cuales incluyen el código para los servicios y mensajes a partir de los archivos .proto
, utilizando el compilador de Protocol Buffers (protobuf).
Info |
---|
Se cuenta con el plugin de protobuf al archivo |
Code Block |
---|
apply plugin 'com.google.protobuf' |
Info |
---|
También, se incluye la siguiente configuración para el plugin: |
Code Block |
---|
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.23.2'
}
plugins{
grpc{
artifact = 'io.grpc:protoc-gen-grpc-java:1.53.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc{
}
}
}
} |
Para que el plugin compile los archivos .proto
se ejecuta el comando gradle build
y se generen los archivos Java necesarios.
Los stubs serán generados en el directorio build/generated/source/proto/main/grpc
.
Note |
---|
Si se desea no utilizar un stub y probar la comunicación con un servidor gRPC , se tendría que implementar manualmente toda la lógica de comunicación, serialización, deserialización y manejo de la comunicación de red, lo que puede ser bastante complejo y propenso a errores. |
Tipos de Stubs en gRPC
Implementación del cliente
Después de generar el código del cliente y del servidor, se implementan los stubs en los script de prueba.
Creación del tipo de Stub
En gRPC en necesario especificar el tipo de stub (cliente) que que se requiere usar para hacer una petición. El tipo de stub que se elija, determina cómo se maneja la petición.
Para seleccionar el tipo de stub, se deben usar los métodos correspondientes de la clase generada automáticamente a partir del .proto
.
Por ejemplo, si el servicio se llama AccountAggregationService
, gRPC generará una clase AccountAggregationServiceGrpc
que contiene métodos: newBlockingStub
, newFutureStub
, y newStub
que se pueden usar para crear los distintos tipos de stubs.
A continuación se especifica como se crea un stub de gRPC bloqueante para la interfaz AccountAggregationService
. Esto es esencialmente un cliente que se usará para hacer llamadas al servicio.
Code Block |
---|
AccountAggregationServiceGrpc.AccountAggregationServiceBlockingStub = AccountAggregationServiceGrpc.newBlockingStub(); |
ServiceBase.java
Se optó por crear una clase padre que mantuviera la principal con una estructura abstracta para que maneje la apertura , y cierre de los canales, la infraestructura necesaria para construir y la creación del tipo de stub que todas las pruebas de servicios GRPC deben tener. De esta manera, las clases hijas son responsables de definir los detalles específicosutilizar "stubs" gRPC, y la configuración de la URL del servidor que todos los tests de servicios gRPC requieren. Las subclases derivadas de ServiceBase
deberán proporcionar la implementación específica de la construcción del stub.
ServiceBase.java es una clase abstracta genérica que proporciona una la estructura básica para la creación de servicios y utiliza y herramientas para configurar una conexión al servicio y comunicarse con él utilizando la librería de gRPC para la creación de canales y stubs.
Esta clase administra un ManagedChannel
y un AbstractStub
(referenciado genéricamente como T
). El ManagedChannel
es el medio principal de comunicación entre el cliente y el servidor en gRPC, y el AbstractStub
es una representación genérica de un servicio gRPC en el lado del cliente.
ServiceBase
se ocupa de la creación y cierre del ManagedChannel
, pero delega la creación del AbstractStub
a las subclases a través del método abstracto buildStub
. El método buildStub
se llama después de que se ha creado el ManagedChannel
, en el método setup
, para que las subclases puedan utilizar el canal para construir su stub.
AccountAggregationServiceBase.java
AccountAggregationServiceBase
Al iniciar una prueba, la clase se conecta a un servicio usando una dirección URL (
url
).Una vez establecida la conexión, crea un "stub" o punto de conexión para comunicarse con el servicio.
Al finalizar una prueba, cierra la conexión.
Code Block |
---|
public abstract class ServiceBase<T extends AbstractStub<T>> extends TestBase |
🛠️ La razón principal para hacer la clase abstracta es que contiene un método abstracto (buildStub
) que las clases hijas deben implementar obligatoriamente.
🔗 T
es un tipo genérico. La clase está diseñada para trabajar con cualquier tipo T
que extienda (o sea un subtipo de) AbstractStub<T>
.
Code Block |
---|
protected abstract T buildStub(ManagedChannel channel); |
El método es abstracto porque como tal, no tiene una implementación en esta clase. Las clases que hereden de esta clase base deben proporcionar una implementación para este método.
Cada servicio en gRPC puede tener su propio stub. Esta función será implementada por las subclases para construir el stub dependiendo del servicio que se esté probando.
Al ser T
es un tipo que extiende de AbstractStub<T>
. El método buildStub
devolverá un objeto de tipo T
, que será una especie de AbstractStub
.
(ManagedChannel channel)
: El método recibirá un parámetro llamado channel
de tipo ManagedChannel
El cual representa una conexión a un servidor gRPC.
Code Block | ||
---|---|---|
| ||
@Before
public void setup() {
channel = ManagedChannelBuilder.forTarget(url)
.usePlaintext()
.intercept(new LoggingClientInterceptor(url))
.build();
blockingStub = buildStub(channel);
}
@After
public void tearDown() throws Exception {
if (channel != null) {
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
}
} |
Estos métodos se utilizan para configurar y limpiar recursos antes y después de cada prueba individual.
🚀 setup()
:
Crea un canal gRPC para comunicarse con un servicio remoto a la url que será proporcionada por la clase que herede de
ServiceBase
.Añade un interceptor de registro. (Para imprimir en el log: Calling URL, Calling method, Sending message y Received response)
Construye un "stub" bloqueante utilizando el canal recién creado.
🧹 tearDown()
:
Verifica si el canal existe.
Si existe, cierra el canal inmediatamente y espera hasta 5 segundos para que se cierre completamente.
MirrorStrategyServiceBase.java
MirrorStrategyServiceBase
es una subclase concreta de ServiceBase
que proporciona una implementación específica del método buildStub
. Esta clase representa un servicio de agregación de cuentas y utiliza el stub de bloqueo específico para este servicio,
AccountAggregationServiceGrpc.AccountAggregationServiceBlockingStub
.
Por lo tanto, AccountAggregationServiceBase
MirrorStrategyServiceBase
se beneficia de la gestión del ManagedChannel
proporcionada por ServiceBase
, y solo necesita preocuparse por la creación del stub correcto para su servicio específico.
Code Block |
---|
public abstract class MirrorStrategyServiceBase extends ServiceBase<AccountAggregationServiceGrpc. |
ManagedChannel
entre varios servicios, manteniendo al mismo tiempo la flexibilidad para utilizar diferentes stubs según las necesidades de cada servicio. Esto resulta en un código más limpio, modular y fácil de mantener.AccountAggregationServiceBlockingStub> { |
En este caso, se le está pasando a ServiceBase
el tipo AccountAggregationServiceGrpc.AccountAggregationServiceBlockingStub
.
Recordemos que AccountAggregationServiceGrpc
es la clase generada automáticamente al compilarse un archivo .proto
. Y AccountAggregationServiceBlockingStub
es un tipo de stub de una clase interna generadas dentro de AccountAggregationServiceGrpc
.
Code Block |
---|
public MirrorStrategyServiceBase() {
setUrl();
} |
Cuando se crea una instancia de esta clase, automáticamente se establece su URL al valor de baseMirrorStrategyADDRESS
usando el método setUrl
.
El valor de baseMirrorStrategyADDRESS
se obtiene de la clase de configuración cuyo origen es el config.properties
Code Block |
---|
public abstract class TestConfig extends Runner {
@BeforeClass
public static void setUp() throws IOException {
if (globalSetup) {
...
baseMirrorStrategyADDRESS = configProperties.getProperty(PropertiesHandler.paths().get("baseMirrorStrategyADDRESS"));
}
}
/**
* End up execution after test class is being executed.
*/
@AfterClass
...
} |