У меня:
протофайл находится отдельно с сервера и клиента
Код: Выделить всё
syntax = "proto3";
package my.proto.file.proto.event;
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
message EventsRequest {
string serviceName = 1;
}
message EventSaveRequest {
Event event = 1;
string eventType = 2;
}
message Event {
string eventId = 1;
string source = 2;
string login = 3;
string role = 4;
string operation = 5;
string description = 6;
optional google.protobuf.Timestamp createdAt = 7;
}
message EventResponse {
repeated Event events = 1;
}
message SaveEventResponse {
Event events = 1;
}
service EventService {
rpc getEventsByServiceName(EventsRequest) returns (stream EventResponse);
rpc saveEvents(EventSaveRequest) returns (SaveEventResponse);
}
Код: Выделить всё
...
grpc:
client:
my-service-client:
address: "localhost:9090"
negotiationType: PLAINTEXT
...
Код: Выделить всё
...
dependencyManagement {
dependencies {
...
dependency("my.proto.file:eventmanager-grpc-proto:1.0.0-SNAPSHOT")
dependency("net.devh:grpc-client-spring-boot-starter:3.1.0.RELEASE")
}
}
dependencies {
implementation("net.devh:grpc-client-spring-boot-starter")
implementation("my.proto.file:eventmanager-grpc-proto")
...
}
...
Код: Выделить всё
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import my.proto.file.proto.event.EventServiceGrpc;
import my.proto.file.proto.event.EventOuterClass;
@Slf4j
@Service
public class EventService {
@GrpcClient("my-service-client")
private EventServiceGrpc.EventServiceBlockingStub blockingStub;
public EventOuterClass.EventResponse getEventsByServiceName(String serviceName) {
EventOuterClass.EventsRequest request = EventOuterClass.EventsRequest
.newBuilder()
.setServiceName(serviceName)
.build();
EventOuterClass.EventResponse response = blockingStub.getEventsByServiceName(request).next();
return response;
}
... // here is the call to saveEvents
}
Код: Выделить всё
...
grpc:
server:
port: 9090
reflection-service-enabled: true
shutdown-grace-period: 0
...
Код: Выделить всё
...
dependencies {
...
implementation("io.grpc:grpc-api:1.63.0")
implementation("io.grpc:grpc-stub:1.63.0")
implementation("io.grpc:grpc-protobuf:1.63.0")
implementation("net.devh:grpc-server-spring-boot-starter:3.1.0.RELEASE")
testImplementation("net.devh:grpc-client-spring-boot-starter:3.1.0.RELEASE")
implementation("org.springdoc:springdoc-openapi-starter-webflux-api")
implementation("org.springdoc:springdoc-openapi-starter-webflux-ui")
implementation("io.netty:netty-all:4.1.110.Final")
implementation("org.javers:javers-core")
implementation("de.codecentric:spring-boot-admin-starter-client:3.3.2")
implementation("io.projectreactor:reactor-tools")
implementation("io.r2dbc:r2dbc-postgresql:0.8.13.RELEASE")
//compile only
compileOnly("org.projectlombok:lombok")
compileOnly ("io.grpc:grpc-netty:1.63.0")
compileOnly ("io.grpc:grpc-protobuf:1.63.0")
compileOnly ("io.grpc:grpc-stub:1.63.0")
compileOnly ("io.grpc:grpc-services:1.63.0")
testImplementation("io.projectreactor:reactor-test")
testImplementation("io.grpc:grpc-testing:1.63.0")
testImplementation("com.salesforce.servicelibs:reactor-grpc-stub:1.2.4")
...
}
dependencyManagement {
...
dependencies {
...
dependency("org.projectlombok:lombok-mapstruct-binding:0.2.0")
dependency("org.springdoc:springdoc-openapi-starter-webflux-api:2.5.0")
dependency("org.springdoc:springdoc-openapi-starter-webflux-ui:2.5.0")
dependency("my.proto.file:eventmanager-grpc-proto:1.0.0-SNAPSHOT")
dependency("org.springframework.cloud:spring-cloud-starter-sleuth:3.1.11")
dependency("org.springframework.cloud:spring-cloud-sleuth-zipkin:3.1.11")
dependency("io.projectreactor:reactor-core:3.6.2")
...
}
}
...
Код: Выделить всё
import my.proto.file.eventmanager.interceptors.LogGrpcInterceptor;
import my.proto.file.eventmanager.mapper.EventMapper;
import my.proto.file.eventmanager.model.Event;
import my.proto.file.proto.event.EventOuterClass;
import my.proto.file.proto.event.ReactorEventServiceGrpc;
import io.micrometer.tracing.Tracer;
import io.micrometer.tracing.annotation.NewSpan;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Validator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
@GrpcService(interceptors = {LogGrpcInterceptor.class})
@Slf4j
@RequiredArgsConstructor
public class GrpcImplEventService extends ReactorEventServiceGrpc.EventServiceImplBase {
private static final Long TIMEOUT_MILLIS = 5000L;
private final EventService eventService;
private final Tracer tracer;
private final Validator validator;
@Override
@NewSpan
public Flux getEventsByServiceName(EventOuterClass.EventsRequest request) {
Flux w = eventService.getEventsByServiceName(request.getServiceName());
return Mono.just(request)
.flatMapMany(req -> eventService.getEventsByServiceName(req.getServiceName())
.doOnNext(ev -> spanTag("source", req.getServiceName()))
.map(
ev -> EventOuterClass.EventResponse.newBuilder().addEvents(EventMapper.INSTANCE.map(ev)).build()
)
)
.timeout(Duration.ofMillis(TIMEOUT_MILLIS))
.doOnError(this::spanError)
.doOnNext(response -> log.info("Events count received: {}", response.getEventsCount()));
}
... // here is the implementation saveEvents, validate, spanTag, spanError
}
[grpc-nio-worker-ELG-1 -5] DEBUG n.d.b.g.c.n.DiscoveryClientNameResolver — запланированное разрешение для localhost:9090
[grpc-default-executor-0] ОШИБКА n.d.b.g.c.n.DiscoveryClientNameResolver — серверы для localhost:9090 не найдены
[grpc-default-executor-0] ПРЕДУПРЕЖДАТЬ io.grpc.internal.ManagedChannelImpl - [Канал: (localhost:9090)] Не удалось разрешить имя. status=Status{code=UNAVAILABLE,description=Серверы для localhost:9090 не найдены, причина=null
[grpc -default-executor-0] DEBUG io.grpc.ChannelLogger - [Канал: (localhost:9090)] Вход в состояние TRANSIENT_FAILURE с средство выбора: фиксированныйResultPicker(PickResult{subchannel=null,streamTracerFactory=null, status=Status{code=UNAVAILABLE,description=Серверы не найдены для localhost:9090, Cause=null}, drop=false})
[grpc-default-executor-0] ОТЛАДКА i.g.i.BackoffPolicyRetryScheduler — планирование отсрочки разрешения DNS на 6 987 791 831 нс
[http-nio-8081-exec-2] ОШИБКА o.a.c.c.C.[.[.[.[dispatcherServlet] — Servlet.service() для сервлет [dispatcherServlet] в контексте с путем [] выдал исключение [ошибка обработки запроса: io.grpc.StatusRuntimeException: UNAVAILABLE: серверы для localhost: 9090 не найдены] с основной причиной io.grpc.StatusRuntimeException: UNAVAILABLE: серверы для localhost не найдены: 9090
[grpc-default-executor-0] ОШИБКА n.d.b.g.c.n.DiscoveryClientNameResolver — серверы для localhost:9090 не найдены
[grpc-default-executor-0] ПРЕДУПРЕЖДЕНИЕ io.grpc.internal.ManagedChannelImpl - [Канал: (localhost:9090)] Не удалось разрешить имя. status=Status{code=UNAVAILABLE,description=Серверы для localhost:9090 не найдены, причина=null
[grpc -default-executor-0] DEBUG io.grpc.ChannelLogger - [Канал: (localhost:9090)] Не удалось разрешить имя: Status{code=UNAVAILABLE,description=Серверы для localhost:9090 не найдены, причина=null
[grpc-default -executor-0] DEBUG io.grpc.ChannelLogger - [Канал: (localhost:9090)] Вход в состояние TRANSIENT_FAILURE с помощью средства выбора: FixResultPicker(PickResult{subchannel=null,streamTracerFactory=null, status=Status{code=UNAVAILABLE,description=Серверы не найдены для localhost:9090, Cause=null}, drop=false})
[http-nio-8081-exec-2] ОТЛАДКА io.grpc.Context - Переопределение хранилища не существует. Использование java.lang.ClassNotFoundException по умолчанию: io.grpc.override.ContextStorageOverride
PS
Если я создам свой собственный bean-компонент и заменю его вместо GrpcClient, все будет работать. Ниже приведен пример работы клиента.
Мой компонент
Код: Выделить всё
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.AbstractBlockingStub;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import my.proto.file.proto.event.EventServiceGrpc;
import my.proto.file.proto.event.EventServiceGrpc.EventServiceBlockingStub;
@Configuration
@ComponentScan(basePackages = "accessportal.controller")
public class MyBeans {
@Bean
public EventServiceBlockingStub EventServiceBlockingStub() {
ManagedChannel channel = ManagedChannelBuilder
.forTarget("localhost:9090")
.usePlaintext().build();
return EventServiceGrpc.newBlockingStub(channel);
}
}
Код: Выделить всё
...
public class EventService {
@Autowired
private EventServiceGrpc.EventServiceBlockingStub blockingStub;
public EventOuterClass.EventResponse getEventsByServiceName(String serviceName) {
EventOuterClass.EventsRequest request = EventOuterClass.EventsRequest
.newBuilder()
.setServiceName(serviceName)
.build();
EventOuterClass.EventResponse response = blockingStub.getEventsByServiceName(request).next();
return response;
}
...// here is the call to saveEvents
}
Структура GrpcClient BlockStub имеет много каналов.

Моя структура BlockStub

Если мне будет недостаточно информации, напишите мне, я дополню свой вопрос.< /p>
Я пробовал разные версии зависимостей. А также вместо реализации GrpcClient я создал свой собственный, и он работает.
Подробнее здесь: https://stackoverflow.com/questions/793 ... oesnt-work
Мобильная версия