GRPC Server
This section describes core concepts that Spring gRPC uses on the server side. We recommend reading it closely to understand the ideas behind how Spring gRPC is implemented.
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 gRPC Service
To create a gRPC server, you need to provide one or more beans of type BindableService
.
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 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.
Netty Server
If you use the spring-grpc-spring-boot-starter
dependency on its own, the Server
is a Netty-based implementation.
You can configure common features of the server by using the grpc.server
prefix in application.properties
or application.yml
.
For instance, to set the port to listen on, use spring.grpc.server.port
(defaults to 9090).
For more specialized configuration, you can provide a ServerBuilderCustomizer
bean to customize the ServerBuilder
before it is used to create the server.
Shaded Netty
You can switch to a shaded Netty provided by the gRPC team by adding the grpc-netty-shaded
dependency and excluding the grpc-netty
dependency.
<dependency>
<groupId>org.springframework.grpc</groupId>
<artifactId>spring-grpc-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
</dependency>
For Gradle users
dependencies {
implementation "org.springframework.grpc:spring-grpc-spring-boot-starter"
implementation 'io.grpc:grpc-netty-shaded'
modules {
module("io.grpc:grpc-netty") {
replacedBy("io.grpc:grpc-netty-shaded", "Use Netty shaded instead of regular Netty")
}
}
}
Servlet Server
Any servlet container can be used to run a gRPC server.
Spring gRPC includes autoconfiguration that configures the server to use the servlet container if it detects that it is in a web application, so all you have to do is include spring-boot-starter-web
and the grpc-servlet
dependnecy in your application.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.grpc</groupId>
<artifactId>spring-grpc-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-servlet-jakarta</artifactId>
</dependency>
For Gradle users
dependencies {
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.grpc:spring-grpc-spring-boot-starter"
implementation "io.grpc:grpc-servlet-jakarta"
}
The spring.grpc.server.
properties will be ignored in favour of the regular server.
properties in this case (with the exception of spring.grpc.server.max-inbound-message-size
).
The servlet that is created is mapped to process HTTP POST requests to the paths defined by the registered services, as /<service-name>/*
.
Clients can connect to the server using that path, which is what any gRPC client library will do.
The gRPC server has fewer configuration options when running in a servlet container, as the servlet container is responsible for the network layer.
You can still add ServerBuilderCustomizer
beans to customize the server as it is built, but some features common in the "native" builders are not available and may throw exceptions at runtime.
Server Interceptors
Global
To add a server interceptor to be applied to all services you can simply register a server interceptor bean and then annotate it with @GlobalServerInterceptor
.
The interceptors are ordered according to their bean natural ordering (i.e. @Order
).
@Bean
@Order(100)
@GlobalServerInterceptor
ServerInterceptor myGlobalLoggingInterceptor() {
return new MyLoggingInterceptor();
}
Per-Service
To add a server interceptor to be applied to a single service you can simply register a server interceptor bean and then annotate your BindableService
bean with @GrpcService
, specifying the interceptor using either the interceptors
or interceptorNames
attribute.
The interceptors are ordered according to their position in the attribute list.
When using both interceptors
and interceptorNames
, the former entries precede the latter.
In the following example, the myServerInterceptor
will be applied to the myService
service.
@Bean
MyServerInterceptor myServerInterceptor() {
return new MyServerInterceptor();
}
@GrpcService(interceptors = MyServerInterceptor.class)
BindableService myService() {
...
}
When a service is configured with both global and per-service interceptors, the global interceptors are first applied in their sorted order followed by the per-service interceptors in their sorted order. However, by setting the You can use this option if you want to add a per-service interceptor between global interceptors. |
Health
Spring gRPC autoconfigures the standard gRPC Health service for performing health check calls against gRPC servers.
The health service is registered with the gRPC server and a HealthStatusManager
bean is provided that can be used to update the health status of your services.
Actuator Health
When Spring Boot Actuator is added to your project and the Health endpoint is available, the framework will automatically periodically update the health status of a configured list of Spring Boot health indicators, including any (custom indicators).
By default, the aggregate status of the individual indicators is also used to update the overall server status (""
).
The following example uses application.yml
to include the health status of the db
and redis
autoconfigured health indicators.
spring:
grpc:
server:
health:
actuator:
health-indicator-paths:
- db
- redis
The items in the health-indicator-paths are the identifiers of the indicator which is typically the name of the indicator bean without the HealthIndicator suffix.
|
You can use the "spring.grpc.server.health.*" application properties to further configure the health feature.
Client-side
Spring gRPC can also autoconfigure the client-side health check feature to your gRPC clients.
To enable health checks on a named channel, simply set the spring.grpc.client.channels.<channel-name>.health.enabled
application property to true
.
To enable health checks for all channels, set the spring.grpc.client.default-channel.enabled
application property to true
.
By default, the health check will consult the overall status service (i.e. ""
).
To use a specific service, use the health.service-name
application property on the desired channel.
The default-load-balancing-policy must be set to round_robin to participate in the health checking. This is the default used by Spring gRPC but if you change the setting you will not get health checks
|
The following example enables health checks for all unknown channels (using the overall server status) and for the channel named one
(using the service service-one
health check).
spring:
grpc:
client:
default-channel:
health:
enabled: true
channels:
one:
health:
enabled: true
service-name: service-one
Observability
Spring gRPC provides an autoconfigured interceptor that can be used to provide observability to your gRPC services.
All you need to do is add Spring Boot actuators to your project, and optionally a bridge to your observability platform of choice (just like any other Spring Boot application).
The grpc-tomcat
sample in the Spring gRPC repository shows how to do it, and you should see trace logging and metrics when you connect to the server.
Exception Handling
Spring gRPC provides an autoconfigured exception handler that can be used to provide a consistent way to handle exceptions in your gRPC services.
All you need to do is add @Beans
of type GrpcExceptionHandler
to your application context, and they will be used to handle exceptions thrown by your services.
A GrpcExceptionHandler
can be used to handle exceptions of a specific type, returning null for those it does not support, or to handle all exceptions.
Testing
If you include spring-grpc-test
in your project, your gRPC server in a @SpringBootTest
will be started in-process (i.e. not listening on a network port).
All clients that connect to any server via the autoconfigured GrpcChannelFactory
will be able to connect to it.
You can switch the in-process server off by setting spring.grpc.in-process.enabled
to false
.
Security
Netty
The netty-based server supports TLS and mTLS out of the box.
To configure the server you can configure an SSL Bundle in the application.properties
or application.yml
file.
An example would be:
spring.grpc.server.ssl.bundle=ssltest
spring.ssl.bundle.jks.ssltest.keystore.location=classpath:test.jks
spring.ssl.bundle.jks.ssltest.keystore.password=secret
spring.ssl.bundle.jks.ssltest.keystore.type=JKS
spring.ssl.bundle.jks.ssltest.key.password=password
Here we configure a bundle named "ssltest" that uses a JKS keystore, similar to what you do with TLS support for Spring Boot in other areas.
It is then applied to the gRPC server using the spring.grpc.server.ssl.bundle
property.
To use self-signed certificates, for testing purposes only, you also need to set spring.grpc.server.ssl.secure=false
.
Servlet
The servlet-based server supports any security configuration that the servlet container supports, including Spring Security.
This means that you can easily implement your favourite authentication and authorization mechanisms.
The server will reject unauthenticated requests with a 401 status code and unauthenticated requests with an invalid token with a 403 status code, as with a normal HTTP API.
It will also send an appropriate WWW-Authenticate
header, e.g. with the value Bearer
to indicate that it is expecting a token (for example).
The gRPC response will also contain a Status
with the appropriate error code and message.
For authorization checking, e.g. role-based access control, your BindableService
beans can be annotated with @PreAuthorize
.
N.B. if you customize the gRPC server call executors, you will need to ensure that you wrap them in a DelegatingSecurityContextExecutor
(from Spring Security).
Spring gRPC handles this for the default configuration.
Spring gRPC will automatically configure the gRPC server interceptors, and Spring Boot will provide defaults for an AuthenticationManager
and a UserDetailsService
.
Spring Boot will also provide default configuration for an OAuth2 resource server, if you set the classpath up correctly (following the Spring Boot documentation) which will be used to validate the token.
You will want to provide your own SecurityFilterChain
because the one provided by Spring Boot will enable CSRF protection for all endpoints, which is not compatible with gRPC.
Here’s an example with HTTP Basic authentication:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.httpBasic(Customizer.withDefaults())
.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated())
.csrf(csrf -> csrf.disable())
.build();
}
Disabling CSRF is fine if you have no other HTTP endpoints, but if you do you will need to be careful to disable CSRF protection for gRPC requests.
To help you do that you can use a GrpcServletRequest
to check if the request is a gRPC request and disable CSRF protection for it.
Example:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
... // configure endpoint paths and authentication patterns
.csrf(csrf -> csrf.ignoringRequestMatchers(GrpcServletRequest.all()))
.build();
}