gRPC Spring Boot Starter
repository·master·Indexed 25 days ago
https://github.com/grpc-ecosystem/grpc-springA library providing automatic configuration for integrating gRPC servers and clients into Spring Boot applications. It includes support for @GrpcService and @GrpcClient annotations, Spring Boot Actuator for gRPC metrics (including gRPC A66 spec), and automatic service registration with discovery implementations such as Consul, Eureka, Nacos, and Zookeeper.
What's inside grpc-spring
- gRPC-Spring-Boot-Starter integrates Google's gRPC framework with Spring Boot. It simplifies the setup of gRPC servers and clients by allowing you to add a single dependency and use annotations on your service classes or client stub fields. The library is designed to complement the standard gRPC experience while providing Spring Boot's ease of configuration and customization.
Understand the gRPC Spring versioning policy
masterThe major version of
grpc-spring-boot-starterindicates compatibility with specific Spring Boot versions:- 1.x.x: End of Life (EOL); no longer receiving updates.
- 2.x.x: Current version; updated alongside Spring Boot or gRPC releases.
- 3.x.x: Current version; updated alongside Spring Boot or gRPC releases.
Minor versions represent feature updates. A minor version bump typically occurs when Spring Boot or gRPC versions are incremented, or when major features are added/changed. While upgrades are usually compatible, gRPC API evolutions may occasionally introduce incompatibilities.
Supported gRPC-Java Flavors
masterThis library provides built-in support for various gRPC implementations. While server-side support is widely available across flavors, client-side support may require customization for non-standard implementations.Configure Mutual Certificate Authentication (mTLS)
masterTo ensure only trustworthy clients can connect, you can enable mutual certificate authentication. This requires providing a collection of trusted client certificates and setting the
clientAuthmode.Steps:
- Create a certificate collection file by concatenating your client certificates:
cat client*.crt > trusted-clients.crt.collection - Configure the server properties with the collection path and the desired
clientAuthmode.
clientAuthmodes:REQUIRE: Client certificate authentication is mandatory.OPTIONAL: The server requests a certificate but does not force the client to provide one. This is useful for securing specific services while allowing unauthenticated access to others.
grpc.server.security.trustCertCollection=file:certificates/trusted-clients.crt.collection grpc.server.security.clientAuth=REQUIRE- Create a certificate collection file by concatenating your client certificates:
Test gRPC components using a Mocked Stub
masterYou can test components by mocking the gRPC stub and injecting it via a setter. This approach is fast and works well with standard mocking frameworks, but it requires extra configuration to handle final classes/methods and does not work for beans using stubs in
@PostConstructor via indirect injection.Implementation Steps:
- Add
mockitoto your dependencies. - Create
src/test/resources/mockito-extensions/org.mockito.plugins.MockMakerwith the contentmock-maker-inlineto allow mocking final classes/methods. - Mock the stub and use a setter to inject it into your component.
public class MyComponentTest { private MyComponent myComponent = new MyComponent(); private ChatServiceBlockingStub chatService = Mockito.mock(ChatServiceBlockingStub.class); @BeforeEach void setup() { myComponent.setChatService(chatService); } @Test void testSayHello() { Mockito.when(chatService.sayHello(...)).thenAnswer(...); assertThat(myComponent.sayHello("ThisIsMyName")).contains("ThisIsMyName"); } }- Add
Set up Cloud Discovery for gRPC services
masterThe gRPC Spring Boot Starter supports automatic service registration with specific discovery implementations. Currently, the supported implementations that provide automatic registration are
consul,eureka,nacos, andzookeeper. Note that while these allow automatic registration, clients do not require additional configuration to use them.1. Start a Discovery Server
Choose one of the following methods to start your discovery service:
Consul:
docker run --name=consul -p 8500:8500 consulEureka:
./gradlew :example:cloud-eureka-server:bootRunNacos:
docker run --env MODE=standalone --name nacos -d --rm -p 8848:8848 nacos/nacos-server2. Run Server and Client with Discovery
Use the
-PdiscoveryGradle property to specify the implementation (consul,eureka, ornacos) when running the examples.Configure Interface Project Dependencies (Maven & Gradle)
masterThe Interface Project requires protobuf and gRPC dependencies to generate Java classes from
.protofiles.Important: For Java 9+ compatibility, use
jakarta.annotation-apiversion1.3.5and do not update it to2.0.0.### Maven (Interface) ```xml <properties> <protobuf.version>3.23.4</protobuf.version> <protobuf-plugin.version>0.6.1</protobuf-plugin.version> <grpc.version>1.58.0</grpc.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <version>1.3.5</version> <optional>true</optional> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.7.0</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>${protobuf-plugin.version}</version> <configuration> <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>Gradle (Interface)
buildscript { ext { protobufVersion = '3.23.4' protobufPluginVersion = '0.8.18' grpcVersion = '1.58.0' } } plugins { id 'java-library' id 'com.google.protobuf' version "${protobufPluginVersion}" } repositories { mavenCentral() } dependencies { implementation "io.grpc:grpc-protobuf:${grpcVersion}" implementation "io.grpc:grpc-stub:${grpcVersion}" compileOnly 'jakarta.annotation:jakarta.annotation-api:1.3.5' } protobuf { protoc { artifact = "com.google.protobuf:protoc:${protobufVersion}" } generatedFilesBaseDir = "$projectDir/src/generated" clean { delete generatedFilesBaseDir } plugins { grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" } } generateProtoTasks { all()*.plugins { grpc {} } } }Configure non-shaded grpc-netty
masterBy default, if
grpc-netty-shadedis on the classpath, this library favors it. To force the use of the non-shadedgrpc-netty, you must explicitly include it and excludegrpc-netty-shadedfrom thegrpc-spring-boot-starter(or the specific server/client starter) dependencies.Maven Example:
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpcVersion}</version> </dependency> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> </exclusion> </exclusions> </dependency>Gradle Example:
implementation "io.grpc:grpc-netty:${grpcVersion}" implementation 'net.devh:grpc-spring-boot-starter:...' exclude group: 'io.grpc', module: 'grpc-netty-shaded'<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpcVersion}</version> </dependency> <!-- For both --> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> </exclusion> </exclusions> </dependency>Add a ServerInterceptor
masterThere are three ways to add a
ServerInterceptorto your gRPC server:- Global Interceptor: Annotate your interceptor with
@GrpcGlobalServerInterceptoror implement aGlobalServerInterceptorConfigurer. - Service-Specific: Explicitly list interceptors in the
@GrpcService#interceptorsor@GrpcService#interceptorNamesfields. - Programmatic: Use a
GrpcServerConfigurerto callserverBuilder.intercept(ServerInterceptor interceptor).
- Global Interceptor: Annotate your interceptor with
Configure Authorization using Spring Annotations
masterYou can use standard Spring Security annotations (like
@Secured) on your gRPC method implementations.Requirements:
- Add
@EnableMethodSecurity(proxyTargetClass = true)to one of your@Configurationclasses.proxyTargetClass = trueis mandatory; otherwise, you will receiveUNIMPLEMENTEDresponses. - Ensure your service implementation extends the generated
ImplBaseclass. - Annotate the implementation methods directly.
- Add
Enable Transport Layer Security (TLS) for gRPC clients
mastergRPC uses
TLSby default. To ensure TLS is enabled for a specific client, verify that thenegotiationTypeproperty is set toTLSor is using its default value.Prerequisites: You must have a compatible
SSL/TLSimplementation on your classpath:grpc-netty-shaded(includes implementation)grpc-netty: Requires adding a dependency tonetty-tcnative-boringssl-static. Ensure you use the exact compatible versions specified in the grpc-java netty security section.
grpc.client.<SomeName>.negotiationType=TLSCreate gRPC Service Definitions
masterPlace your
.protofiles insrc/main/proto. The configured Maven or Gradle plugins will useprotocandprotoc-gen-grpc-javato generate:- Data classes: For request and response messages.
- ImplBase classes: Base logic for implementing service methods.
- Stub classes: Complete client implementations.
syntax = "proto3"; package net.devh.boot.grpc.example; option java_multiple_files = true; option java_package = "net.devh.boot.grpc.examples.lib"; option java_outer_classname = "HelloWorldProto"; // The greeting service definition. service MyService { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) { } } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; }