Skip to content

Commit

Permalink
Add support for registering service definition bean
Browse files Browse the repository at this point in the history
  • Loading branch information
dsyer committed Nov 6, 2024
1 parent 7fed50a commit f0ec4b1
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ This section describes core concepts that Spring gRPC uses on the server side. W
You only need to provide one or more beans of type `BindableService` to create a gRPC server, provided the classpath contains an implementation of a `Server`. The `BindableService` is a gRPC service that can be bound to a server.
The `Server` is the gRPC server that listens for incoming requests and routes them to the appropriate service implementation.

== Create a `BindableService`
== Create a gRPC Service

To create a gRPC server, you need to provide one or more beans of type `BindableService`.
To create a gRPC server, you need to provide one or more beans of type `BindableService` or `ServerServiceDefinition`.
There are some `BindableServices` available off the shelf that you could include in your application (an example is the reflection service from the `grpc-services` artifact which allows clients to browse the metadata of your services and download the Portobuf files).
Very commonly, you will create your own `BindableService` by extending the generated service implementation from your Protobuf file.
The easiest way to do it is to simply add a Spring `@Service` annotation to the implementation class and have it picked up by the `@ComponentScan` in your Spring Boot application.
The easiest way to activate it is to simply add a Spring `@Service` annotation to the implementation class and have it picked up by the `@ComponentScan` in your Spring Boot application.
Alternatively, you could create an instance of it in a `@Configuration` class and return it as a bean, or return it's `ServerServiceDefinition`.
The last option is useful if you need to add specific behaviour, like an interceptor, to the service.
It is an error to have more than one instance of the same service name, so don't create both a `BindableService` and a `ServerServiceDefinition` bean for the same service.

== Netty Server

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.grpc.autoconfigure.server;

import java.util.ArrayList;
import java.util.List;

import io.grpc.BindableService;
Expand All @@ -35,13 +36,20 @@ class DefaultGrpcServiceDiscoverer implements GrpcServiceDiscoverer {

private final ObjectProvider<BindableService> grpcServicesProvider;

DefaultGrpcServiceDiscoverer(ObjectProvider<BindableService> grpcServicesProvider) {
private ObjectProvider<ServerServiceDefinition> grpcServiceDefinitionsProvider;

DefaultGrpcServiceDiscoverer(ObjectProvider<BindableService> grpcServicesProvider,
ObjectProvider<ServerServiceDefinition> grpcServiceDefinitionsProvider) {
this.grpcServicesProvider = grpcServicesProvider;
this.grpcServiceDefinitionsProvider = grpcServiceDefinitionsProvider;
}

@Override
public List<ServerServiceDefinition> findServices() {
return grpcServicesProvider.orderedStream().map(BindableService::bindService).toList();
List<ServerServiceDefinition> list = new ArrayList<>(
grpcServicesProvider.orderedStream().map(BindableService::bindService).toList());
list.addAll(grpcServiceDefinitionsProvider.orderedStream().toList());
return list;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.grpc.CompressorRegistry;
import io.grpc.DecompressorRegistry;
import io.grpc.ServerBuilder;
import io.grpc.ServerServiceDefinition;

/**
* {@link EnableAutoConfiguration Auto-configuration} for gRPC server-side components.
Expand Down Expand Up @@ -75,8 +76,9 @@ ServerBuilderCustomizers serverBuilderCustomizers(ObjectProvider<ServerBuilderCu

@ConditionalOnMissingBean
@Bean
GrpcServiceDiscoverer grpcServiceDiscoverer(ObjectProvider<BindableService> bindableServicesProvider) {
return new DefaultGrpcServiceDiscoverer(bindableServicesProvider);
GrpcServiceDiscoverer grpcServiceDiscoverer(ObjectProvider<BindableService> bindableServicesProvider,
ObjectProvider<ServerServiceDefinition> serviceDefinitionsProvider) {
return new DefaultGrpcServiceDiscoverer(bindableServicesProvider, serviceDefinitionsProvider);
}

@ConditionalOnBean(CompressorRegistry.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ void grpcServiceDiscovererAutoConfiguredAsExpected() {
.containsExactly(this.serviceDefinition));
}

@Test
void grpcServiceDiscovererWithServiceDefinitionAsExpected() {
ServerServiceDefinition serviceDefinition = ServerServiceDefinition.builder("my-other-service").build();
this.contextRunnerWithLifecyle()
.withBean(ServerServiceDefinition.class, () -> serviceDefinition)
.run((context) -> assertThat(context).getBean(GrpcServiceDiscoverer.class)
.extracting(GrpcServiceDiscoverer::findServices,
InstanceOfAssertFactories.list(ServerServiceDefinition.class))
.containsExactly(this.serviceDefinition, serviceDefinition));
}

@Test
void whenHasUserDefinedServerBuilderCustomizersDoesNotAutoConfigureBean() {
ServerBuilderCustomizers customCustomizers = mock(ServerBuilderCustomizers.class);
Expand Down

0 comments on commit f0ec4b1

Please sign in to comment.