{"id":13500142,"url":"https://github.com/LogNet/grpc-spring-boot-starter","last_synced_at":"2025-03-29T05:33:04.870Z","repository":{"id":38198291,"uuid":"50572514","full_name":"LogNet/grpc-spring-boot-starter","owner":"LogNet","description":"Spring Boot starter module for gRPC  framework. ","archived":false,"fork":false,"pushed_at":"2024-01-22T13:58:19.000Z","size":17134,"stargazers_count":2241,"open_issues_count":53,"forks_count":435,"subscribers_count":84,"default_branch":"master","last_synced_at":"2025-03-27T22:08:05.893Z","etag":null,"topics":["grpc","grpc-framework","grpc-service","java","spring","spring-boot","spring-boot-starter","spring-cloud"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LogNet.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-28T09:39:21.000Z","updated_at":"2025-03-09T17:49:11.000Z","dependencies_parsed_at":"2024-06-18T19:59:31.234Z","dependency_job_id":null,"html_url":"https://github.com/LogNet/grpc-spring-boot-starter","commit_stats":null,"previous_names":[],"tags_count":83,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LogNet%2Fgrpc-spring-boot-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LogNet%2Fgrpc-spring-boot-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LogNet%2Fgrpc-spring-boot-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LogNet%2Fgrpc-spring-boot-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LogNet","download_url":"https://codeload.github.com/LogNet/grpc-spring-boot-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246145012,"owners_count":20730494,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","grpc-framework","grpc-service","java","spring","spring-boot","spring-boot-starter","spring-cloud"],"created_at":"2024-07-31T22:00:51.738Z","updated_at":"2025-03-29T05:33:04.839Z","avatar_url":"https://github.com/LogNet.png","language":"Java","readme":"= Spring boot starter for http://www.grpc.io/[gRPC framework.]\nifdef::env-github[]\n:tip-caption: :bulb:\n:note-caption: :information_source:\n:important-caption: :heavy_exclamation_mark:\n:caution-caption: :fire:\n:warning-caption: :warning:\nendif::[]\n:toc:\n\nimage:https://img.shields.io/maven-central/v/io.github.lognet/grpc-spring-boot-starter.svg?label=Maven%20Central[link=https://search.maven.org/search?q=g:%22io.github.lognet%22%20AND%20a:%22grpc-spring-boot-starter%22]\nimage:https://app.travis-ci.com/LogNet/grpc-spring-boot-starter.svg?branch=master[\"Build Status\", link=\"https://app.travis-ci.com/LogNet/grpc-spring-boot-starter\"]\nimage:https://codecov.io/gh/LogNet/grpc-spring-boot-starter/branch/master/graph/badge.svg[\"Codecov\",link=\"https://codecov.io/gh/LogNet/grpc-spring-boot-starter/branch/master\"]\nimage:https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg[\"Stand With Ukraine\",link=\"https://stand-with-ukraine.pp.ua\"]\n\n:toc:\n:source-highlighter: prettify\n:numbered:\n:icons: font\n\n\n\n== Features\n\nAutoconfigures and runs the embedded gRPC server with @GRpcService-enabled beans as part of spring-boot application (https://github.com/LogNet/grpc-spring-boot-starter/blob/master/images/demo.gif[short video])\n\n== Setup\n\n\n=== Long story short\n\n`Gradle` users are advised to apply the plugin :\n\n[source,groovy]\n----\nplugins {\nid \"io.github.lognet.grpc-spring-boot\" version '5.1.5'\n}\n----\n\nlink:./grpc-spring-boot-starter-gradle-plugin/README.adoc[io.github.lognet.grpc-spring-boot^]   gradle plugin dramatically simplifies the project setup.\n\n=== Short story long\n\n[source,groovy]\n----\nrepositories {\n  mavenCentral()\n  // maven { url \"https://oss.sonatype.org/content/repositories/snapshots\" } // for snapshot builds\n}\ndependencies {\n  implementation 'io.github.lognet:grpc-spring-boot-starter:5.1.5'\n}\n----\n\nBy default, starter pulls `io.grpc:grpc-netty-shaded`   as transitive dependency, if you are forced to use pure `grpc-netty` dependency:\n\n[source,groovy]\n----\nimplementation ('io.github.lognet:grpc-spring-boot-starter:5.1.5') {\n  exclude group: 'io.grpc', module: 'grpc-netty-shaded'\n}\nimplementation 'io.grpc:grpc-netty:1.58.0' // \u003c1\u003e\n----\n\u003c1\u003e Make sure to pull the version that matches the release.\n\nBoth libraries' presence on classpath is also xref:_netty_server[supported] with `grpc.netty-server.on-collision-prefer-shaded-netty` property.\n\nIf you are using Spring Boot Dependency Management plugin, it might pull not the same version as the version this started was compiled against, causing binary incompatibility issue. +\nIn  this case you'll need to forcibly and explicitly set the  `grpc` version to use (see link:ReleaseNotes.md[version matrix here^] ):\n\n[source,groovy]\n----\nconfigurations.all {\n  resolutionStrategy.eachDependency { details -\u003e\n    if (\"io.grpc\".equalsIgnoreCase(details.requested.group)) {\n      details.useVersion \"1.58.0\"\n    }\n  }\n}\n----\n\n[NOTE]\nThe release notes with compatibility matrix can be found link:ReleaseNotes.md[here^]\n\nFollow this https://github.com/google/protobuf-gradle-plugin[guide^]  to generate stub and server interface(s) from your `.proto` file(s). +\n\nIf you are stack with maven - use this https://www.google.com/search?q=protobuf+maven+plugin[link^].\n\n== Usage\n\n\n* Annotate your server interface implementation(s) with `@org.lognet.springboot.grpc.GRpcService`\n* Optionally configure the server port in your `application.yml/properties`.\nDefault port is `6565`.\n\n[source,yaml]\n----\n grpc:\n    port: 6565\n----\n\n[NOTE]\nA random port can be defined by setting the port to `0`. +\nThe actual port being used can then be retrieved by using `@LocalRunningGrpcPort` annotation on `int` field which will inject the running port (explicitly configured or randomly selected)\n\n* Optionally enable server reflection (see https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md)\n\n[source,yaml]\n----\n grpc:\n    enableReflection: true\n----\n\n\n* Optionally set the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/SmartLifecycle.html[startup phase order] (defaults to `Integer.MAX_VALUE`).\n\n[source,yaml]\n----\n grpc:\n    start-up-phase: XXX\n----\n\n* Optionally set the number of seconds to wait for preexisting calls to finish during graceful server shutdown.\nNew calls will be rejected during this time.\nA negative value is equivalent to an infinite grace period.\nDefault value is `0` (means don't wait).\n\n[source,yaml]\n----\n grpc:\n    shutdownGrace: 30\n----\n\n* link:grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/GRpcServerProperties.java[Netty-specific server properties] can be specified under `grpc.netty-server` prefix. +\nBy configuring one of the `grpc.netty-server.xxxx` values you are implicitly setting transport to be Netty-based.\n\n[[_netty_server]]\n[source,yaml]\n----\ngrpc:\n  netty-server:\n    keep-alive-time: 30s \u003c1\u003e\n    max-inbound-message-size: 10MB \u003c2\u003e\n    primary-listen-address: 10.10.15.23:0 \u003c3\u003e\n    additional-listen-addresses:\n      - 192.168.0.100:6767 \u003c4\u003e\n    on-collision-prefer-shaded-netty: false \u003c5\u003e\n\n----\n\u003c1\u003e `Duration` type properties can be configured with string value format described https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/convert/DurationStyle.java[here].\n\u003c2\u003e `DataSize` type properties can be configured with string value described  https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/unit/DataSize.html#parse-java.lang.CharSequence-[here]\n\u003c3\u003e Exposed on external network IP with custom port. +\n`SocketAddress` type properties string value format:\n* `host:port` (if `port` value is less than 1, uses random value)\n* `host:`  (uses default grpc port, `6565` )\n\u003c4\u003e Exposed on internal network IP as well with predefined port `6767`.\n\u003c5\u003e In case you have both `shaded` and `pure` netty libraries in dependencies, pick the `NettyServerBuilder` type that should be created. This is the type that will be passed to `GRpcServerBuilderConfigurer` (see \u003c\u003cCustom gRPC Server Configuration\u003e\u003e), defaults to `true`(i.e. `io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder`; `io.grpc.netty.NettyServerBuilder` if `false`)\n\nThe starter supports also the `in-process server`, which should be used for testing purposes :\n\n[source,yaml]\n----\n grpc:\n    enabled: false \u003c1\u003e\n    inProcessServerName: myTestServer \u003c2\u003e\n----\n\u003c1\u003e Disables the default server (`NettyServer`).\n\u003c2\u003e Enables the `in-process` server.\n\n[NOTE]\nIf you enable both the `NettyServer` and `in-process` server, they will both share the same instance of `HealthStatusManager` and `GRpcServerBuilderConfigurer` (see \u003c\u003cCustom gRPC Server Configuration\u003e\u003e).\n\n== Showcase\n\nIn the `grpc-spring-boot-starter-demo` project you can find fully functional examples with integration tests. +\n\n=== Service implementation\n\nThe service definition from `.proto` file looks like this :\n\n[source,proto]\n----\nservice Greeter {\n    rpc SayHello ( HelloRequest) returns (  HelloReply) {}\n}\n----\n\nNote the generated `io.grpc.examples.GreeterGrpc.GreeterImplBase` class that extends `io.grpc.BindableService`.\n\nAll you need to do is to annotate your service implementation with `@org.lognet.springboot.grpc.GRpcService`\n\n[source,java]\n----\n    @GRpcService\n    public static class GreeterService extends  GreeterGrpc.GreeterImplBase{\n        @Override\n        public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver\u003cGreeterOuterClass.HelloReply\u003e responseObserver) {\n            final GreeterOuterClass.HelloReply.Builder replyBuilder = GreeterOuterClass.HelloReply.newBuilder().setMessage(\"Hello \" + request.getName());\n            responseObserver.onNext(replyBuilder.build());\n            responseObserver.onCompleted();\n        }\n    }\n----\n\n=== Interceptors support\n\nThe starter supports the registration of two kinds of interceptors: _Global_ and _Per Service_. +\nIn both cases the interceptor has to implement `io.grpc.ServerInterceptor` interface.\n\n- Per service\n\n[source,java]\n----\n@GRpcService(interceptors = { LogInterceptor.class })\npublic  class GreeterService extends  GreeterGrpc.GreeterImplBase{\n    // ommited\n}\n----\n\n`LogInterceptor` will be instantiated via spring factory if there is bean of type `LogInterceptor`, or via no-args constructor otherwise.\n\n- Global\n\n[source,java]\n----\n@GRpcGlobalInterceptor\npublic  class MyInterceptor implements ServerInterceptor{\n    // ommited\n}\n----\n\nThe annotation on java config factory method is also supported :\n\n[source,java]\n----\n @Configuration\n public class MyConfig{\n     @Bean\n     @GRpcGlobalInterceptor\n     public  ServerInterceptor globalInterceptor(){\n         return new ServerInterceptor(){\n             @Override\n             public \u003cReqT, RespT\u003e ServerCall.Listener\u003cReqT\u003e interceptCall(ServerCall\u003cReqT, RespT\u003e call, Metadata headers, ServerCallHandler\u003cReqT, RespT\u003e next) {\n                // your logic here\n                 return next.startCall(call, headers);\n             }\n         };\n     }\n }\n----\n\nThe particular service also has the opportunity to disable the global interceptors :\n\n[source,java]\n----\n@GRpcService(applyGlobalInterceptors = false)\npublic  class GreeterService extends  GreeterGrpc.GreeterImplBase{\n    // ommited\n}\n----\n==== Interceptors ordering\n\nGlobal interceptors can be ordered using Spring's `@Ordered` or `@Priority` annotations.\nFollowing Spring's ordering semantics, lower order values have higher priority and will be executed first in the interceptor chain.\n\n[source,java]\n----\n@GRpcGlobalInterceptor\n@Order(10)\npublic  class A implements ServerInterceptor{\n    // will be called before B\n}\n\n@GRpcGlobalInterceptor\n@Order(20)\npublic  class B implements ServerInterceptor{\n    // will be called after A\n}\n----\n\nThe starter uses built-in interceptors to implement error handling, Spring `Security`, `Validation` and `Metrics` integration.\nTheir order can also be controlled by below properties :\n\n* `grpc.recovery.interceptor-order` (error handling interceptor order, defaults to `Ordered.HIGHEST_PRECEDENCE`)\n* `grpc.security.auth.interceptor-order` ( defaults to `Ordered.HIGHEST_PRECEDENCE+1`)\n* `grpc.validation.interceptor-order` ( defaults to `Ordered.HIGHEST_PRECEDENCE+10`)\n* `grpc.metrics.interceptor-order` ( defaults to `Ordered.HIGHEST_PRECEDENCE+20`)\n\nThis gives you the ability to set up the desired order of built-in and your custom interceptors.\n\n*Keep on reading !!! There is more*\n\nThe way grpc interceptor works is that it intercepts the call and returns the server call listener, which in turn can intercept the request message as well, before forwarding it to the actual service call handler :\n\nimage:./images/interceptors_001.png[]\n\n\nBy setting  `grpc.security.auth.fail-fast`  property to `false` all downstream interceptors as well as all upstream interceptors (On_Message) will still be executed in case of authentication/authorization failure +\n\nAssuming `interceptor_2` is `securityInterceptor` :\n\n* For failed authentication/authorization with  `grpc.security.auth.fail-fast=true`(default): +\n+\nimage:./images/interceptors_002.png[]\n\n\n* For failed authentication/authorization with `grpc.security.auth.fail-fast=false`: +\n+\nimage:./images/interceptors_003.png[]\n\n\n=== Distributed tracing support (Spring Cloud Sleuth integration)\n\nThis started is *natively* supported by `spring-cloud-sleuth` project. +\nPlease continue to https://docs.spring.io/spring-cloud-sleuth/docs/current/reference/html/integrations.html#sleuth-rpc-grpc-integration[sleuth grpc integration].\n\n\n=== GRPC server metrics (Micrometer.io integration)\n\nBy including `org.springframework.boot:spring-boot-starter-actuator` dependency,\nthe starter will collect gRPC server metrics , broken down by\n\n. `method` - gRPC service method FQN (Fully Qualified Name)\n. `result` - https://grpc.github.io/grpc-java/javadoc/io/grpc/Status.Code.html[Response status code]\n. `address` - server local address (if you exposed additional  listen addresses, with `grpc.netty-server.additional-listen-addresses` property)\n\nAfter configuring the exporter of your https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics[choice],\nyou should see the `timer` named `grpc.server.calls`.\n\n==== Custom tags support\n\nBy defining `GRpcMetricsTagsContributor` bean in your application context, you can add custom tags to the `grpc.server.calls` timer. +\nYou can also use `RequestAwareGRpcMetricsTagsContributor` bean to tag *unary* and *streaming* calls. +\nDemo is https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/GrpcMeterTest.java[here]\n\n[TIP]\nKeep the dispersion low not to blow up the cardinality of the metric.\n\n`RequestAwareGRpcMetricsTagsContributor` can be still executed for failed authentication if `metric` interceptor has higher precedence than `security` interceptor and   `grpc.security.auth.fail-fast` set to `false`. +\nThis case is covered by link:grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/MetricWithSecurityTest.java[this] test. +\n\n[TIP]\nMake sure to read \u003c\u003cInterceptors ordering\u003e\u003e chapter.\n\n==== Exposing Prometheus endpoint\n\nMake sure to include below dependencies :\n\n[source]\n----\nimplementation \"org.springframework.boot:spring-boot-starter-actuator\"\nimplementation \"io.micrometer:micrometer-registry-prometheus\"\nimplementation 'org.springframework.boot:spring-boot-starter-web'\n----\n\nConfiguration :\n\n[source,yml]\n----\nmanagement:\n  metrics:\n    export:\n      prometheus:\n        enabled: true\n  endpoints:\n    web:\n      exposure:\n        include: \"*\"\n----\n\nStandard `/actuator/metrics` and `/actuator/prometheus` endpoints will render `grpc.server.calls` metrics (see demo https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/DemoAppTest.java[here]).\n\n[NOTE]\nGRPC scrapping https://github.com/prometheus/prometheus/issues/8414[proposal]\n\n=== Spring Boot Validation support\n\nThe starter can be  autoconfigured to validate request/response gRPC service messages.\nPlease continue to \u003c\u003cImplementing message validation\u003e\u003e for configuration details.\n\n=== Spring cloud stream support\n\nThe starter internally defines the bean of type `java.util.function.Consumer` which is being considered  for function registry when `spring-cloud-stream` is on classpath, which is undesirable (`spring-cloud-stream` auto-registers the channel if you have exactly one Consumer/Supplier/Function bean in the application context, so you already have one if you use  this starter together with `spring-cloud-stream`).\n\nAccording to  https://github.com/spring-cloud/spring-cloud-function/issues/418[this],  it is  recommended to use `spring.cloud.function.definition` property in production ready applications and not to rely on the auto-discovery.\n\nPlease  refer to https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/kafkaStreamTest/java/org/lognet/springboot/grpc/kafka/GrpcKafkaTest.java[GRPC Kafka Stream demo], the essential part is https://github.com/LogNet/grpc-spring-boot-starter/blob/0784a007c15ac479e5d9e19a22b943f9852244b9/grpc-spring-boot-starter-demo/src/kafkaStreamTest/resources/bootstrap-kafka-test.yml#L22[this] line.\n\n=== Spring security support\n\nThe starter provides built-in support for authenticating and authorizing users leveraging integration with https://spring.io/projects/spring-security[Spring Security framework]. +\nPlease refer to the sections on \u003c\u003cSpring Security Integration\u003e\u003e for details on  supported authentication providers and configuration options.\n\n=== Transport Security (TLS)\n\nThe transport security can be configured using root certificate together with its private key path:\n\n[source,yaml]\n----\n grpc:\n    security:\n      cert-chain: classpath:cert/server-cert.pem\n      private-key: file:../grpc-spring-boot-starter-demo/src/test/resources/cert/server-key.pem\n----\n\nThe value of both properties is in form supported by https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/io/ResourceEditor.html[ResourceEditor]. +\n\nThe client side should be configured accordingly :\n\n[source,java]\n----\n((NettyChannelBuilder)channelBuilder)\n .useTransportSecurity()\n .sslContext(GrpcSslContexts.forClient().trustManager(certChain).build());\n----\n\nThis starter will pull the `io.netty:netty-tcnative-boringssl-static` dependency by default to support SSL. +\nIf you need another SSL/TLS support, please exclude this dependency and follow https://github.com/grpc/grpc-java/blob/master/SECURITY.md[Security Guide].\n\n[NOTE]\nIf the more detailed tuning is needed for security setup, please use custom configurer described in \u003c\u003cCustom gRPC Server Configuration\u003e\u003e\n\n=== Custom gRPC Server Configuration\n\nTo intercept the `io.grpc.ServerBuilder` instance used to build the `io.grpc.Server`, you can add bean that inherits from `org.lognet.springboot.grpc.GRpcServerBuilderConfigurer` to your context and override the `configure` method. +\nMultiple configurers are also supported. +\nBy the time of invocation of `configure` method, all discovered services, including theirs interceptors, had been added to the passed builder. +\nIn your implementation of `configure` method, you can add your custom configuration:\n\n[source,java]\n----\n@Component\npublic class MyGRpcServerBuilderConfigurer extends GRpcServerBuilderConfigurer{\n        @Override\n        public void configure(ServerBuilder\u003c?\u003e serverBuilder){\n            serverBuilder\n                .executor(YOUR EXECUTOR INSTANCE)\n                .useTransportSecurity(YOUR TRANSPORT SECURITY SETTINGS);\n            ((NettyServerBuilder)serverBuilder)// cast to NettyServerBuilder (which is the default server) for further customization\n                    .sslContext(GrpcSslContexts  // security fine tuning\n                                    .forServer(...)\n                                    .trustManager(...)\n                                    .build())\n                    .maxConnectionAge(...)\n                    .maxConnectionAgeGrace(...);\n\n        }\n    };\n}\n@Component\npublic class MyCustomCompressionGRpcServerBuilderConfigurer extends GRpcServerBuilderConfigurer{\n        @Override\n        public void configure(ServerBuilder\u003c?\u003e serverBuilder){\n            serverBuilder\n                .compressorRegistry(YOUR COMPRESSION REGISTRY)\n                .decompressorRegistry(YOUR DECOMPRESSION REGISTRY) ;\n\n        }\n    };\n}\n----\n\n[NOTE]\nIf you enable both `NettyServer` and `in-process` servers, the `configure` method will be invoked on the same instance of configurer. +\nIf you need to differentiate between the passed `serverBuilder` s, you can check the type. +\nThis is the current limitation.\n\n== Events\n`GRpcServerInitializedEvent` is published upon server startup, you can consume it using regular spring API.\n\n== Reactive API support\n\nStarting from version `5.1.0`, https://github.com/LogNet/grpc-spring-boot-starter/tree/master/grpc-spring-boot-starter-gradle-plugin[spring-boot-starter-gradle-plugin]\nintegrates SalesForce's https://github.com/salesforce/reactive-grpc[reactive-grpc] protoc plugin :\n\n[source,groovy]\n----\nimport org.lognet.springboot.grpc.gradle.ReactiveFeature\nplugins {\n  id \"io.github.lognet.grpc-spring-boot\"\n}\ngrpcSpringBoot {\n  reactiveFeature.set(ReactiveFeature.REACTOR) // or ReactiveFeature.RX\n}\n----\n\nHere are the https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/reactiveTest/java/org/lognet/springboot/grpc/reactive/ReactiveDemoTest.java[tests] and   https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/main/java/org/lognet/springboot/grpc/demo/ReactiveGreeterGrpcService.java[reactive grpc sample service].\n\n== Error handling\n\nThe starter registers the `GRpcExceptionHandlerInterceptor` which is responsible to propagate the service-thrown exception to the error handlers. +\nThe error handling method could be registered by having `@GRpcServiceAdvice` annotated bean with methods annotated with `@GRpcExceptionHandler` annotations. +\nThese are considered as `global` error handlers and the method with exception type parameter the nearest by the type hierarchy to the thrown exception is invoked. +\nThe signature of the error handler has to follow the below pattern:\n\n|===\n|Return type |Parameter 1 |Parameter 2\n\n|io.grpc.Status\n|any `Exception` type\n|GRpcExceptionScope\n\n\n\n|===\n\n\n\n[source,java]\n.Sample\n----\n@GRpcServiceAdvice\nclass MyHandler1{\n    @GRpcExceptionHandler\n    public Status handle (MyCustomExcpetion exc, GRpcExceptionScope scope){\n\n    }\n    @GRpcExceptionHandler\n    public Status handle (IllegalArgumentException exc, GRpcExceptionScope scope){\n\n    }\n\n}\n@GRpcServiceAdvice\nclass MyHandler2 {\n    @GRpcExceptionHandler\n   public Status anotherHandler (NullPointerException npe,GRpcExceptionScope scope){\n\n   }\n}\n----\n\nYou can have as many `advice` beans and handler methods as you want as long as they don't interfere with each other and don't create handled exception type ambiguity.\n\nThe `grpc` service bean is also discovered for error handlers, having the higher precedence than global error handling methods discovered in  `@GRpcServiceAdvice` beans. The service-level error handling methods are considered `private` and invoked only when the exception is thrown by *this* service:\n\n[source,java]\n.Sample\n----\nclass SomeException extends Exception{\n\n}\nclass SomeRuntimeException extends RuntimeException{\n\n}\n\n@GRpcService\npublic  class HelloService extends GreeterGrpc.GreeterImplBase{\n    @Override\n    public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver\u003cGreeterOuterClass.HelloReply\u003e responseObserver) {\n        ...\n    throw new GRpcRuntimeExceptionWrapper(new SomeException()) ; // \u003c1\u003e\n//or\n    throw new GRpcRuntimeExceptionWrapper(new SomeException(), \"myHint\");// \u003c2\u003e\n//or\n    throw new SomeRuntimeException(); //\u003c3\u003e\n    }\n   @GRpcExceptionHandler\n   public Status privateHandler (SomeException npe,GRpcExceptionScope scope){\n        // INVOKED when thrown from  HelloService service\n        String myHint = scope.getHintAs(String.class);   // \u003c4\u003e\n        scope.getResponseHeaders().put(Metadata.Key.of(\"custom\", Metadata.ASCII_STRING_MARSHALLER), \"Value\");// \u003c5\u003e\n   }\n   @GRpcExceptionHandler\n   public Status privateHandler (SomeRuntimeException npe,GRpcExceptionScope scope){\n        // INVOKED when thrown from  HelloService service\n\n   }\n}\n@GRpcServiceAdvice\nclass MyHandler  {\n   @GRpcExceptionHandler\n   public Status anotherHandler (SomeException npe,GRpcExceptionScope scope){\n        // NOT INVOKED when thrown from  HelloService service\n   }\n   @GRpcExceptionHandler\n   public Status anotherHandler (SomeRuntimeException npe,GRpcExceptionScope scope){\n        // NOT INVOKED when thrown from  HelloService service\n   }\n\n}\n----\n\u003c1\u003e Because the nature of `grpc` service API that doesn't allow throwing checked exception, the special runtime exception type is provided to wrap the checked exception. It's then getting unwrapped when looking for the handler method.\n\u003c2\u003e When throwing the `GRpcRuntimeExceptionWrapper` exception, you can also pass the `hint` object which is then accessible from the `scope` object in `handler` method.\n\u003c3\u003e Runtime exception can be thrown as-is and doesn't need to be wrapped.\n\u003c4\u003e Obtain the hint object.\n\u003c5\u003e Send custom headers to the client.\n\nAuthentication failure is propagated via `AuthenticationException` and authorization failure  - via `AccessDeniedException`.\n\nValidation failure is propagated via `ConstraintViolationException`: for  failed request - with `Status.INVALID_ARGUMENT` as a  hint , and for  failed response  - with `Status.FAILED_PRECONDITION` as a hint.\n\nThe demo is link:grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/recovery/GRpcRecoveryTest.java[here]\n\n== Implementing message validation\n\nThanks to https://beanvalidation.org/2.0/spec/[Bean Validation] configuration support via https://beanvalidation.org/2.0/spec/#xml[XML deployment descriptor] , it's possible to\nprovide the constraints for generated classes via XML instead of instrumenting the generated messages with custom `protoc` compiler.\n\n. Add `org.springframework.boot:spring-boot-starter-validation` dependency to your project.\n. Create `META-INF/validation.xml` and constraints declarations file(s). (IntelliJ IDEA has great auto-complete support for authorizing bean validation constraints xml files ) +\nSee also https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=6.1#chapter-xml-configuration[samples] from `Hibernate` validator documentation\n\nYou can find  link:grpc-spring-boot-starter-demo/src/main/resources/META-INF/validation/constraints-person.xml[demo configuration] and corresponding tests\nlink:grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/ValidationTest.java[here]\n\nNote, that both `request` and `response` messages are being validated.\n\nIf your gRPC method uses the same request and response message type, you can use `org.lognet.springboot.grpc.validation.group.RequestMessage` and\n`org.lognet.springboot.grpc.validation.group.ResponseMessage` validation groups to apply different validation logic  :\n\n[source,xml]\n----\n...\n\u003cgetter name=\"someField\"\u003e\n\t\u003c!--should be empty for request message--\u003e\n\t\u003cconstraint annotation=\"javax.validation.constraints.Size\"\u003e\n\t\t\u003cgroups\u003e\n\t\t\t\u003cvalue\u003eorg.lognet.springboot.grpc.validation.group.RequestMessage\u003c/value\u003e \u003c1\u003e\n\t\t\u003c/groups\u003e\n\t\t\u003celement name=\"min\"\u003e0\u003c/element\u003e\n\t\t\u003celement name=\"max\"\u003e0\u003c/element\u003e\n\t\u003c/constraint\u003e\n\t\u003c!--should NOT  be empty for response message--\u003e\n\t\u003cconstraint annotation=\"javax.validation.constraints.NotEmpty\"\u003e\n\t\t\u003cgroups\u003e\n\t\t\t\u003cvalue\u003eorg.lognet.springboot.grpc.validation.group.ResponseMessage\u003c/value\u003e \u003c2\u003e\n\t\t\u003c/groups\u003e\n\t\u003c/constraint\u003e\n\u003c/getter\u003e\n...\n----\n\u003c1\u003e Apply this constraint only for `request` message\n\u003c2\u003e Apply this constraint only for `response` message\n\n\nNote also custom cross-field link:grpc-spring-boot-starter-demo/src/main/java/org/lognet/springboot/grpc/demo/PersonConstraint.java[constraint] and its usage :\n\n[source,xml]\n----\n\u003cbean class=\"io.grpc.examples.GreeterOuterClass$Person\"\u003e\n\t\u003cclass\u003e\n\t\t\u003cconstraint annotation=\"org.lognet.springboot.grpc.demo.PersonConstraint\"/\u003e\n\t\u003c/class\u003e\n    \u003c!-- ... --\u003e\n\u003c/bean\u003e\n----\n\nAs described in  \u003c\u003cInterceptors ordering\u003e\u003e chapter, you can give `validation` interceptor the higher precedence than `security` interceptor and set `grpc.security.auth.fail-fast` property to `false`. +\nIn this scenario, if call is both unauthenticated and invalid, the client will get `Status.INVALID_ARGUMENT` instead of `Status.PERMISSION_DENIED/Status.UNAUTHENTICATED` response status.\nDemo is https://github.com/LogNet/grpc-spring-boot-starter/blob/master/grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/auth/ValidationWithSecurityTest.java[here]\n\n\n\n\n\n== GRPC response observer  and Spring @Transactional caveats\nWhile it's still possible to have your rpc methods annotated with `@Transactional` (with `spring.aop.proxy-target-class=true` if it's not enabled by default), chances are to get unpredictable behaviour. Consider below grpc method implementation :\n\n[source,java]\n----\n@GRpcService\nclass MyGrpcService extends ...{\n    @Autowired\n    private MyJpaRepository repo;\n\n    @Transactional //\u003c1\u003e\n    public void rpcCall(Req request, StreamOvserver\u003cRes\u003e observer) {\n        Res response = // Database operations via repo\n        observer.onNext(response); //\u003c2\u003e\n        observer.onCompleted();\n    }//\u003c3\u003e\n}\n----\n\u003c1\u003e The method is annotated as `@Transactional`, Spring will commit the transaction **at some time after methods returns**\n\u003c2\u003e Response is returned to the caller\n\u003c3\u003e Methods returns, transaction *eventually* committed.\n\n\n\nTheoretically, and as you can see - https://github.com/LogNet/grpc-spring-boot-starter/issues/187[practically], there is small time-span when client (if the network latency is minimal, and your grpc server encouraged context switch right after \u003c2\u003e) can try to access the database via another grpc call *before* the transaction is committed.\n\nThe  solution to overcome this situation is to externalize the transactional logic into separate service class :\n\n[source,java]\n----\n@Service\nclass MyService{\n    @Autowired\n    private MyJpaRepository repo;\n\n    @Transactional //\u003c1\u003e\n    public Res doTransactionalWork(){\n        // Database operations via repo\n        return result;\n    }//\u003c2\u003e\n}\n@GRpcService\nclass MyGrpcService extends ...{\n    @Autowired\n    private MyService myService;\n\n    public void rpcCall(Req request, StreamOvserver\u003cRes\u003e observer) {\n        Res response = myService.doTransactionalWork();\n        observer.onNext(response); //\u003c3\u003e\n        observer.onCompleted();\n    }\n}\n----\n\u003c1\u003e Service method is transactional\n\u003c2\u003e Transaction is *eventually* committed.\n\u003c3\u003e Reply *after* transaction is committed.\n\nBy following this approach you also decouple the transport layer and business logic that now can be tested separately.\n\n\n\n\n\n\n== Spring Security Integration\n\n=== Setup\n\n.Dependencies to implement authentiction scheme (to be added to server-side project)\n[cols=\"1,4\"]\n|===\n|Scheme |Dependencies\n\n|Basic\na|\n* `org.springframework.security:spring-security-config`\n\n\n|Bearer\na|\n* `org.springframework.security:spring-security-config`\n* `org.springframework.security:spring-security-oauth2-jose`\n* `org.springframework.security:spring-security-oauth2-resource-server`\n\n\n|_Custom_\na|\n* `org.springframework.security:spring-security-config`\n* `your.custom.lib`\n\n|===\n\n=== Server side configuration\n\nGRPC security configuration follows the same principals and APIs as Spring WEB security configuration, it's  enabled by default if you have `org.springframework.security:spring-security-config`  dependency in your classpath.\n\nYou can use `@Secured` annotation on services/methods to protect your endpoints, or by using API and overriding defaults (which precesses `@Secured` annotation ):\n\n[source,java]\n----\n @Configuration\n   class MySecurityCfg extends GrpcSecurityConfigurerAdapter {\n        @Override\n        public void configure(GrpcSecurity builder) throws Exception {\n            MethodsDescriptor\u003c?,?\u003e adminMethods = MyServiceGrpc.getSomeMethod();\n            builder\n                    .authorizeRequests()\n                    .methods(adminMethods).hasAnyRole(\"admin\")\n                    .anyMethodExcluding(adminMethods).hasAnyRole(\"user\")\n                    .withSecuredAnnotation();\u003c1\u003e\n        }\n    }\n----\n\u003c1\u003e or combine `API` with `@Secured` annotations.\n\n==== Default\n\n\nThis default configuration secures GRPC methods/services annotated with `org.springframework.security.access.annotation.@Secured`  annotation. +\nLeaving  value of the annotation empty (`@Secured({})`) means : `authenticate` only, no authorization will be performed.\n\nIf `JwtDecoder` bean exists in your context, it will also register `JwtAuthenticationProvider` to handle the validation of authentication claim.\n\n`BasicAuthSchemeSelector` and `BearerTokenAuthSchemeSelector` are also automatically registered to support authentication with username/password and bearer token.\n\nBy setting `grpc.security.auth.enabled` to `false`, GRPC security can be turned-off.\n\n==== Custom\n\nCustomization of GRPC security configuration is done by extending `GrpcSecurityConfigurerAdapter` (Various configuration examples and test scenarios are link:grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/auth[here].)\n\n\n\n[source,java]\n----\n    @Configuration\n    public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {\n        @Autowired\n        private JwtDecoder jwtDecoder;\n\n        @Override\n        public void configure(GrpcSecurity builder) throws Exception {\n\n            builder.authorizeRequests()\u003c1\u003e\n                    .methods(GreeterGrpc.getSayHelloMethod()).hasAnyAuthority(\"SCOPE_profile\")\u003c2\u003e\n            .and()\n                    .authenticationProvider(JwtAuthProviderFactory.withAuthorities(jwtDecoder));\u003c3\u003e\n        }\n    }\n----\n\u003c1\u003e Get hold of authorization configuration object\n\u003c2\u003e `MethodDefinition` of `sayHello` method is allowed for authenticated users with `SCOPE_profile` authority.\n\u003c3\u003e Use `JwtAuthenticationProvider` to validate user claim (`BEARER` token) against resource server configured with `spring.security.oauth2.resourceserver.jwt.issuer-uri` property.\n\n==== DIY\n\nOne is possible to plug in your own bespoke authentication provider by implementing `AuthenticationSchemeSelector` interface.\n\n[source,java]\n----\n@Configuration\n    public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {\n    @Override\n        public void configure(GrpcSecurity builder) throws Exception {\n        builder.authorizeRequests()\n                    .anyMethod().authenticated()//\u003c1\u003e\n                    .and()\n                    .authenticationSchemeSelector(new AuthenticationSchemeSelector() { //\u003c2\u003e\n                            @Override\n                            public Optional\u003cAuthentication\u003e getAuthScheme(CharSequence authorization) {\n                                return new MyAuthenticationObject();// \u003c3\u003e\n                            }\n                        })\n                    .authenticationProvider(new AuthenticationProvider() {// \u003c4\u003e\n                        @Override\n                        public Authentication authenticate(Authentication authentication) throws AuthenticationException {\n                            MyAuthenticationObject myAuth= (MyAuthenticationObject)authentication;\n                            //validate myAuth\n                            return MyValidatedAuthenticationObject(withAuthorities);//\u003c5\u003e\n                        }\n\n                        @Override\n                        public boolean supports(Class\u003c?\u003e authentication) {\n                            return MyAuthenticationObject.class.isInstance(authentication);\n                        }\n                    });\n }\n }\n----\n\u003c1\u003e Secure all services methods.\n\u003c2\u003e Register your own `AuthenticationSchemeSelector`.\n\u003c3\u003e Based on provided authorization header - return `Authentication` object as a claim (not authenticated yet)\n\u003c4\u003e Register your own `AuthenticationProvider` that supports validation of `MyAuthenticationObject`\n\u003c5\u003e Validate provided `authentication` and return validated and *authenticated* `Authentication` object\n\n\n`AuthenticationSchemeSelector` can also be registered by defining Spring bean in your application context:\n\n[source,java]\n----\n@Bean\npublic AuthenticationSchemeSelector myCustomSchemeSelector(){\n     return authHeader-\u003e{\n         // your logic here\n     };\n}\n----\n\n\u003c\u003cClient side configuration support\u003e\u003e section explains how to pass custom authorization scheme and claim from GRPC client.\n\n=== @PreAuthorize() and @PostAuthorize() support\nStarting from version `4.5.9` you can also use standard `@PreAuthorize` and `@PostAuthorize` annotations on grpc service methods and grpc service types.\n\n.Referencing input/output object in expression\n[cols=\"1,1,2,6\"]\n|===\n|Call Type |Input object ref  |Output object ref | Sample\n\n|Unary +\n(request-response)\n|By parameter name\na|`returnObject`\na|\n[source,java]\n----\n@Override\n@PreAuthorize(\"#person.age\u003c12\")\n@PostAuthorize(\"returnObject.description.length()\u003e0\")\npublic void unary(Person person, StreamObserver\u003cAssignment\u003e responseObserver) {\n    }\n----\n\n|Input stream, +\nsingle response\na|`#p0` or `#a0`\na|`returnObject`\na|\n[source,java]\n----\n@Override\n@PreAuthorize(\"#p0.getAge()\u003c12\")\n@PostAuthorize(\"returnObject.description.length()\u003e0\")\npublic StreamObserver\u003cPerson\u003e inStream(StreamObserver\u003cAssignment\u003e responseObserver) {\n    }\n----\n\n|Single request, +\noutput stream\n|By parameter name\na|`returnObject`\na|\n[source,java]\n----\n@Override\n@PreAuthorize(\"#person.age\u003c12\")\n@PostAuthorize(\"returnObject.description.length()\u003e0\")\npublic void outStream(Person person, StreamObserver\u003cAssignment\u003e responseObserver) {\n}\n----\n\n|Bidi stream\n|`#p0` or `#a0`\na|`returnObject`\na|\n[source,java]\n----\n@Override\n@PreAuthorize(\"#p0.age\u003c12\")\n@PostAuthorize(\"returnObject.description.length()\u003e0\")\npublic StreamObserver\u003cPerson\u003e bidiStream(StreamObserver\u003cAssignment\u003e responseObserver) {\n}\n----\n|===\n\n\n=== Obtaining Authentication details\n\nTo obtain  `Authentication` object in the implementation of *secured method*, please use below snippet\n\n[source,java]\n----\nfinal Authentication auth = GrpcSecurity.AUTHENTICATION_CONTEXT_KEY.get();\n----\n\nStarting from `4.5.6`, the `Authentication` object can also be obtained via standard Spring API :\n\n[source,java]\n----\nfinal Authentication auth = SecurityContextHolder.getContext().getAuthentication();\n----\n\n\n=== Client side configuration support\n\nBy adding `io.github.lognet:grpc-client-spring-boot-starter` dependency to your *java grpc client* application you can easily configure per-channel or per-call credentials :\n\nPer-channel::\n+\n[source,java]\n----\nclass MyClient{\n    public void doWork(){\n        final AuthClientInterceptor clientInterceptor = new AuthClientInterceptor(\u003c1\u003e\n                AuthHeader.builder()\n                    .bearer()\n                    .binaryFormat(true)\u003c3\u003e\n                    .tokenSupplier(this::generateToken)\u003c4\u003e\n        );\n\n        Channel authenticatedChannel = ClientInterceptors.intercept(\n                ManagedChannelBuilder.forAddress(\"host\", 6565).build(), clientInterceptor \u003c2\u003e\n        );\n        // use authenticatedChannel to invoke GRPC service\n    }\n\n     private ByteBuffer generateToken(){ \u003c4\u003e\n         // generate bearer token against your resource server\n     }\n }\n----\n\u003c1\u003e Create client interceptor\n\u003c2\u003e Intercept channel\n\u003c3\u003e Turn the binary format on/off: +\n* When `true`, the authentication header is sent with  `Authorization-bin` key using https://grpc.github.io/grpc-java/javadoc/io/grpc/Metadata.BinaryMarshaller.html[binary marshaller].\n* When `false`, the authentication header is sent with  `Authorization` key using https://grpc.github.io/grpc-java/javadoc/io/grpc/Metadata.AsciiMarshaller.html[ASCII marshaller].\n\u003c4\u003e Provide token generator function (Please refer to link:grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/auth/JwtAuthBaseTest.java[for example].)\n\nPer-call::\n+\n[source,java]\n----\nclass MyClient{\n    public void doWork(){\n        AuthCallCredentials callCredentials = new AuthCallCredentials( \u003c1\u003e\n                AuthHeader.builder().basic(\"user\",\"pwd\".getBytes())\n        );\n\n        final SecuredGreeterGrpc.SecuredGreeterBlockingStub securedFutureStub = SecuredGreeterGrpc.newBlockingStub(ManagedChannelBuilder.forAddress(\"host\", 6565));\u003c2\u003e\n\n        final String reply = securedFutureStub\n                .withCallCredentials(callCredentials)\u003c3\u003e\n                .sayAuthHello(Empty.getDefaultInstance()).getMessage();\n\n    }\n }\n----\n\u003c1\u003e Create call credentials with basic scheme\n\u003c2\u003e Create service stub\n\u003c3\u003e Attach call credentials to the call\n+\n`AuthHeader` could also be built with bespoke authorization scheme :\n+\n[source,java]\n----\n AuthHeader\n   .builder()\n   .authScheme(\"myCustomAuthScheme\")\n   .tokenSupplier(()-\u003egenerateMyCustomToken())\n----\n\n== Health check\n\nThe starter registers the default implementation of https://github.com/grpc/grpc-java/blob/bab1fe38dc/services/src/main/java/io/grpc/protobuf/services/HealthServiceImpl.java[HealthServiceImpl]. +\nYou can provide you own by registering link:./grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/health/ManagedHealthStatusService.java[ManagedHealthStatusService] bean in your application context.\n\n\n== Spring actuator support\n\nIf you have   `org.springframework.boot:spring-boot-starter-actuator` and `org.springframework.boot:spring-boot-starter-web` in the classpath, the starter will expose:\n\n* `grpc` health indicator under `/actuator/health` endpoint.\n* `/actuator/grpc` endpoint.\n\nThis can be controlled by standard https://docs.spring.io/spring-boot/docs/2.5.x/reference/html/actuator.html#actuator.endpoints.enabling[endpoints] and https://docs.spring.io/spring-boot/docs/2.5.x/reference/html/actuator.html#actuator.endpoints.health[health] configuration.\n\n== Consul Integration\n\nStarting from version `3.3.0`, the starter will auto-register the running grpc server in Consul registry if `org.springframework.cloud:spring-cloud-starter-consul-discovery` is in classpath and\n`spring.cloud.service-registry.auto-registration.enabled` is *NOT* set to `false`. +\n\nThe registered service name will be prefixed with `grpc-` ,i.e. `grpc-${spring.application.name}` to not interfere with standard registered web-service name if you choose to run both embedded `Grpc` and `Web` servers. +\n\n`ConsulDiscoveryProperties` are bound from configuration properties prefixed by  `spring.cloud.consul.discovery` and then the values are overwritten by `grpc.consul.discovery` prefixed properties (if set). This allows you to have separate consul discovery configuration for `rest` and `grpc` services if you choose to expose both from your application.\n\n[source,yml]\n----\nspring:\n  cloud:\n    consul:\n      discovery:\n        metadata:\n          myKey: myValue \u003c1\u003e\n        tags:\n          - myWebTag \u003c2\u003e\ngrpc:\n  consul:\n    discovery:\n      tags:\n        - myGrpcTag \u003c3\u003e\n----\n\u003c1\u003e Both `rest` and `grpc` services are registered with metadata `myKey=myValue`\n\u003c2\u003e Rest services are registered with  `myWebTag`\n\u003c3\u003e Grpc services are registered with  `myGrpcTag`\n\nSetting `spring.cloud.consul.discovery.register-health-check` (or `grpc.consul.discovery.register-health-check`) to `true` will register GRPC health check service with Consul.\n\n\nThere are 4 supported registration  modes :\n\n. `SINGLE_SERVER_WITH_GLOBAL_CHECK` (default) +\n In this mode the running grpc server is registered as single service with single `grpc` check with empty `serviceId`. +\nPlease note that default implementation https://github.com/grpc/grpc-java/blob/bab1fe38dc50d4178955b79cfb1636afd2aa64df/services/src/main/java/io/grpc/protobuf/services/HealthServiceImpl.java#L64[does nothing] and simply returns `SERVING` status. You might want to provide  your custom \u003c\u003cHealth check\u003e\u003e implementation for this mode.\n. `SINGLE_SERVER_WITH_CHECK_PER_SERVICE` +\nIn this mode the running grpc server is registered as single service with check per each discovered `grpc` service.\n. `STANDALONE_SERVICES` +\nIn this mode each discovered grpc service is  registered as single service with single check. Each registered service is tagged by its own service name.\n. `NOOP` - no grpc services registered. This mode is useful if you serve both `rest` and `grpc` services in your application, but for some reason, only `rest` services should be registered with Consul.\n\n[source,yml]\n.You can control the desired mode from application.properties\n----\ngrpc:\n  consule:\n    registration-mode: SINGLE_SERVER_WITH_CHECK_PER_SERVICE\n\n----\n\n\n\n== Eureka Integration\n\nWhen building production-ready services, the advise is to have separate project for your service(s) gRPC API that holds only proto-generated classes both for server and client side usage. +\nYou will then add this project as `implementation` dependency to your `gRPC client` and `gRPC server` projects.\n\nTo integrate `Eureka` simply follow the great https://spring.io/guides/gs/service-registration-and-discovery/[guide] from Spring.\n\nBelow are the essential parts of configurations for both server and client projects.\n\n===  gRPC Server Project\n\n* Add eureka starter as dependency of your server project together with generated classes from `proto` files:\n\n[source,gradle]\n.build.gradle\n----\n dependencies {\n     implementation('org.springframework.cloud:spring-cloud-starter-eureka')\n     implementation project(\":yourProject-api\")\n }\n----\n\n* Configure gRPC server to register itself with Eureka.\n+\n[source,yaml]\n.bootstrap.yaml\n----\nspring:\n    application:\n        name: my-service-name \u003c1\u003e\n----\n\u003c1\u003e Eureka's `ServiceId` by default is the spring application name, provide it before the service registers itself with Eureka.\n+\n[source,yaml]\n.application.yaml\n----\ngrpc:\n    port: 6565 \u003c1\u003e\neureka:\n    instance:\n        nonSecurePort: ${grpc.port} \u003c2\u003e\n    client:\n        serviceUrl:\n            defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ \u003c3\u003e\n----\n\u003c1\u003e Specify the port number the gRPC is listening on.\n\u003c2\u003e Register the eureka service port to be the same as `grpc.port` so client will know where to send the requests to.\n\u003c3\u003e Specify the registry URL, so the service will register itself with.\n\n\n* Expose the gRPC service as part of Spring Boot Application.\n+\n[source,java]\n.EurekaGrpcServiceApp.java\n----\n @SpringBootApplication\n @EnableEurekaClient\n public class EurekaGrpcServiceApp {\n\n     @GRpcService\n     public static class GreeterService extends GreeterGrpc.GreeterImplBase {\n         @Override\n         public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver\u003cGreeterOuterClass.HelloReply\u003e responseObserver) {\n\n         }\n     }\n\n     public static void main(String[] args) {\n         SpringApplication.run(DemoApp.class,args);\n     }\n }\n----\n\n===  gRPC Client Project\n\n* Add eureka starter as dependency of your client project together with generated classes from `proto` files:\n\n[source,gradle]\n.build.gradle\n----\n dependencies {\n     implementation('org.springframework.cloud:spring-cloud-starter-eureka')\n     implementation project(\":yourProject-api\")\n }\n----\n\n* Configure client to find the eureka service registry:\n\n[source,yaml]\n.application.yaml\n----\neureka:\n  client:\n    register-with-eureka: false \u003c1\u003e\n    service-url:\n      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ \u003c2\u003e\n----\n\u003c1\u003e `false` if this project is not meant to act as a service to another client.\n\u003c2\u003e  Specify the registry URL, so this client will know where to look up the required service.\n\n[source,java]\n.GreeterServiceConsumerApplication.java\n----\n@EnableEurekaClient\n@SpringBootApplication\npublic class GreeterServiceConsumerApplication {\n public static void main(String[] args) {\n   SpringApplication.run(GreeterServiceConsumerApplication.class, args);\n }\n}\n----\n\n* Use EurekaClient to get the coordinates of gRPC service instance from Eureka and consume the service :\n\n[source,java]\n.GreeterServiceConsumer.java\n----\n@EnableEurekaClient\n@Component\npublic class GreeterServiceConsumer {\n    @Autowired\n    private EurekaClient client;\n\n    public void greet(String name) {\n        final InstanceInfo instanceInfo = client.getNextServerFromEureka(\"my-service-name\", false);//\u003c1\u003e\n        final ManagedChannel channel = ManagedChannelBuilder.forAddress(instanceInfo.getIPAddr(), instanceInfo.getPort())\n                .usePlaintext()\n                .build(); //\u003c2\u003e\n        final GreeterServiceGrpc.GreeterServiceFutureStub stub = GreeterServiceGrpc.newFutureStub(channel); //\u003c3\u003e\n        stub.greet(name); //\u003c4\u003e\n\n    }\n}\n----\n\u003c1\u003e Get the information about the `my-service-name` instance.\n\u003c2\u003e Build `channel` accordingly.\n\u003c3\u003e Create stub using the `channel`.\n\u003c4\u003e Invoke the service.\n\n== License\n\nApache 2.0\n","funding_links":[],"categories":["Server","Language-Specific","Java","spring-boot-starter","\u003ca name=\"Java\"\u003e\u003c/a\u003eJava"],"sub_categories":["Java","非官方"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLogNet%2Fgrpc-spring-boot-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLogNet%2Fgrpc-spring-boot-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLogNet%2Fgrpc-spring-boot-starter/lists"}