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 blendWithGlobalInterceptors attribute on the @GrpcService annotation to "true" you can change this behavior so that the interceptors are all combined and then sorted according to their bean natural ordering (i.e. @Order).

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();
}