1 Star 0 Fork 0

dhuaqiao/grpc-spring-boot-starter

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

Spring boot starter for gRPC framework.

grpc spring boot starter Build Status Codecov Best viewed with Octoree

1. Features

Auto-configures and runs the embedded gRPC server with @GRpcService-enabled beans as part of spring-boot application.

2. Setup

repositories {
    mavenCentral()
   //maven { url "https://oss.sonatype.org/content/repositories/snapshots" } //for snapshot builds

}
dependencies {
    compile 'io.github.lognet:grpc-spring-boot-starter:4.5.3'
}

By default, starter pulls io.grpc:grpc-netty-shaded as transitive dependency, if you are forced to use pure grpc-netty dependency:

 compile ('io.github.lognet:grpc-spring-boot-starter:4.4.7') {
  exclude group: 'io.grpc', module: 'grpc-netty-shaded'
 }
 compile 'io.grpc:grpc-netty:1.37.0' // (1)
  1. Make sure to pull the version that matches the release.

Both libraries' presence on classpath is also supported with grpc.netty-server.on-collision-prefer-shaded-netty property.

If 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.
In this case you’ll need to forcibly and explicitly set the grpc version to use (see version matrix here ):

configurations.all {
 resolutionStrategy.eachDependency { details ->
    if ("io.grpc".equalsIgnoreCase(details.requested.group)) {
        details.useVersion "1.37.0"
        }
    }
}
:information_source:
The release notes with compatibility matrix can be found here

3. Usage

  • Start by generating stub and server interface(s) from your .proto file(s).

  • Annotate your server interface implementation(s) with @org.lognet.springboot.grpc.GRpcService

  • Optionally configure the server port in your application.yml/properties. Default port is 6565.

 grpc:
    port: 6565
:information_source:
A random port can be defined by setting the port to 0.
The 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)
 grpc:
    enableReflection: true
 grpc:
    start-up-phase: XXX
  • Optionally set the number of seconds to wait for preexisting calls to finish during graceful server shutdown. New calls will be rejected during this time. A negative value is equivalent to an infinite grace period. Default value is 0 (means don’t wait).

 grpc:
    shutdownGrace: 30
  • Netty-specific server properties can be specified under grpc.netty-server prefix.
    By configuring one of the grpc.netty-server.xxxx values you are implicitly setting transport to be Netty-based.

grpc:
  netty-server:
    keep-alive-time: 30s (1)
    max-inbound-message-size: 10MB (2)
    primary-listen-address: 10.10.15.23:0 (3)
    additional-listen-addresses:
      - 192.168.0.100:6767 (4)
    on-collision-prefer-shaded-netty: false (5)
  1. Duration type properties can be configured with string value format described here.

  2. DataSize type properties can be configured with string value described here

  3. Exposed on external network IP with custom port.
    SocketAddress type properties string value format:

    • host:port (if port value is less than 1, uses random value)

    • host: (uses default grpc port, 6565 )

  4. Exposed on internal network IP as well with predefined port 6767.

  5. 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 Custom gRPC Server Configuration), defaults to true(i.e. io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; io.grpc.netty.NettyServerBuilder if false)

The starter supports also the in-process server, which should be used for testing purposes :

 grpc:
    enabled: false (1)
    inProcessServerName: myTestServer (2)
  1. Disables the default server (NettyServer).

  2. Enables the in-process server.

:information_source:
If you enable both the NettyServer and in-process server, they will both share the same instance of HealthStatusManager and GRpcServerBuilderConfigurer (see Custom gRPC Server Configuration).

4. Show case

In the grpc-spring-boot-starter-demo project you can find fully functional examples with integration tests.

4.1. Service implementation

The service definition from .proto file looks like this :

service Greeter {
    rpc SayHello ( HelloRequest) returns (  HelloReply) {}
}

Note the generated io.grpc.examples.GreeterGrpc.GreeterImplBase class that extends io.grpc.BindableService.(The generated classes were intentionally committed for demo purposes).

All you need to do is to annotate your service implementation with @org.lognet.springboot.grpc.GRpcService

    @GRpcService
    public static class GreeterService extends  GreeterGrpc.GreeterImplBase{
        @Override
        public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
            final GreeterOuterClass.HelloReply.Builder replyBuilder = GreeterOuterClass.HelloReply.newBuilder().setMessage("Hello " + request.getName());
            responseObserver.onNext(replyBuilder.build());
            responseObserver.onCompleted();
        }
    }

4.2. Interceptors support

The starter supports the registration of two kinds of interceptors: Global and Per Service.
In both cases the interceptor has to implement io.grpc.ServerInterceptor interface.

  • Per service

@GRpcService(interceptors = { LogInterceptor.class })
public  class GreeterService extends  GreeterGrpc.GreeterImplBase{
    // ommited
}

LogInterceptor will be instantiated via spring factory if there is bean of type LogInterceptor, or via no-args constructor otherwise.

  • Global

@GRpcGlobalInterceptor
public  class MyInterceptor implements ServerInterceptor{
    // ommited
}

The annotation on java config factory method is also supported :

 @Configuration
 public class MyConfig{
     @Bean
     @GRpcGlobalInterceptor
     public  ServerInterceptor globalInterceptor(){
         return new ServerInterceptor(){
             @Override
             public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
                // your logic here
                 return next.startCall(call, headers);
             }
         };
     }
 }

The particular service also has the opportunity to disable the global interceptors :

@GRpcService(applyGlobalInterceptors = false)
public  class GreeterService extends  GreeterGrpc.GreeterImplBase{
    // ommited
}

4.2.1. Interceptors ordering

Global interceptors can be ordered using Spring’s @Ordered or @Priority annotations. Following Spring’s ordering semantics, lower order values have higher priority and will be executed first in the interceptor chain.

@GRpcGlobalInterceptor
@Order(10)
public  class A implements ServerInterceptor{
    // will be called before B
}

@GRpcGlobalInterceptor
@Order(20)
public  class B implements ServerInterceptor{
    // will be called after A
}

The starter uses built-in interceptors to implement Spring Security, Validation and Metrics integration. Their order can also be controlled by below properties :

  • grpc.security.auth.interceptor-order ( defaults to Ordered.HIGHEST_PRECEDENCE)

  • grpc.validation.interceptor-order ( defaults to Ordered.HIGHEST_PRECEDENCE+10)

  • grpc.metrics.interceptor-order ( defaults to Ordered.HIGHEST_PRECEDENCE+20)

This gives you the ability to setup the desired order of built-in and your custom interceptors.

Keep on reading !!! There is more

The 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 :

interceptor_1(interceptCall)interceptor_2(interceptCall)interceptor_3(interceptCall)
interceptor_1(On_Message)interceptor_2(On_Message)interceptor_3(On_Message)
actual service call

By 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

Assuming interceptor_2 is securityInterceptor :

  • For failed authentication/authorization with grpc.security.auth.fail-fast=true(default):

    interceptor_1(interceptCall)securityInterceptor(interceptCall) - Call is Closed interceptor_3(interceptCall)
    interceptor_1(On_Message)securityInterceptor(On_Message)→`interceptor_3(On_Message)
    `actual service call

  • For failed authentication/authorization with grpc.security.auth.fail-fast=false:

    interceptor_1(interceptCall)securityInterceptor(interceptCall)interceptor_3(interceptCall)interceptor_1(On_Message)securityInterceptor(On_Message) - Call is Closed interceptor_3(On_Message)
    actual service call

4.3. Distributed tracing support (Spring Cloud Sleuth integration)

This started is natively supported by spring-cloud-sleuth project.
Please continue to sleuth grpc integration.

4.4. GRPC server metrics (Micrometer.io integration)

By including org.springframework.boot:spring-boot-starter-actuator dependency, the starter will collect gRPC server metrics , broken down by

  1. method - gRPC service method FQN (Fully Qualified Name)

  2. result - Response status code

  3. address - server local address (if you exposed additional listen addresses, with grpc.netty-server.additional-listen-addresses property)

After configuring the exporter of your choice, you should see the timer named grpc.server.calls.

4.4.1. Custom tags support

By defining GRpcMetricsTagsContributor bean in your application context, you can add custom tags to the grpc.server.calls timer.
You can also use RequestAwareGRpcMetricsTagsContributor bean to tag unary calls.
Demo is here

:bulb:
Keep the dispersion low not to blow up the cardinality of the metric.

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.
This case is covered by this test.

:bulb:
Make sure to read Interceptors ordering chapter.

4.4.2. Exposing Prometheus endpoint

Make sure to include below dependencies :

implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "io.micrometer:micrometer-registry-prometheus"
implementation 'org.springframework.boot:spring-boot-starter-web'

Configuration :

management:
  metrics:
    export:
      prometheus:
        enabled: true
  endpoints:
    web:
      exposure:
        include: "*"

Standard /actuator/metrics and /actuator/prometheus endpoints will render grpc.server.calls metrics (see demo here).

:information_source:
GRPC scrapping proposal

4.5. Spring Boot Validation support

The starter can be auto-configured to validate request/response gRPC service messages. Please continue to Implementing message validation for configuration details.

4.6. Spring security support

The starter provides built-in support for authenticating and authorizing users leveraging integration with Spring Security framework.
Please refer to the sections on Spring Security Integration for details on supported authentication providers and configuration options.

4.7. Transport Security (TLS)

The transport security can be configured using root certificate together with its private key path:

 grpc:
    security:
      cert-chain: classpath:cert/server-cert.pem
      private-key: file:../grpc-spring-boot-starter-demo/src/test/resources/cert/server-key.pem

The value of both properties is in form supported by ResourceEditor.

The client side should be configured accordingly :

((NettyChannelBuilder)channelBuilder)
 .useTransportSecurity()
 .sslContext(GrpcSslContexts.forClient().trustManager(certChain).build());

This starter will pull the io.netty:netty-tcnative-boringssl-static dependency by default to support SSL.
If you need another SSL/TLS support, please exclude this dependency and follow Security Guide.

:information_source:
If the more detailed tuning is needed for security setup, please use custom configurer described in Custom gRPC Server Configuration

4.8. Custom gRPC Server Configuration

To 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.
By the time of invocation of configure method, all discovered services, including theirs interceptors, had been added to the passed builder.
In your implementation of configure method, you can add your custom configuration:

@Component
public class MyGRpcServerBuilderConfigurer extends GRpcServerBuilderConfigurer{
        @Override
        public void configure(ServerBuilder<?> serverBuilder){
            serverBuilder
                .executor(YOUR EXECUTOR INSTANCE)
                .compressorRegistry(YOUR COMPRESSION REGISTRY)
                .decompressorRegistry(YOUR DECOMPRESSION REGISTRY)
                .useTransportSecurity(YOUR TRANSPORT SECURITY SETTINGS);
            ((NettyServerBuilder)serverBuilder)// cast to NettyServerBuilder (which is the default server) for further customization
                    .sslContext(GrpcSslContexts  // security fine tuning
                                    .forServer(...)
                                    .trustManager(...)
                                    .build())
                    .maxConnectionAge(...)
                    .maxConnectionAgeGrace(...);

        }
    };
}
:information_source:
If you enable both NettyServer and in-process servers, the configure method will be invoked on the same instance of configurer.
If you need to differentiate between the passed serverBuilder s, you can check the type.
This is the current limitation.

5. Implementing message validation

Thanks to Bean Validation configuration support via XML deployment descriptor , it’s possible to provide the constraints for generated classes via XML instead of instrumenting the generated messages with custom protoc compiler.

  1. Add org.springframework.boot:spring-boot-starter-validation dependency to your project.

  2. Create META-INF/validation.xml and constraints declarations file(s). (IntelliJ IDEA has great auto-complete support for authorizing bean validation constraints xml files )
    See also samples from Hibernate validator documentation

You can find demo configuration and corresponding tests here

Note, that both request and response messages are being validated.

If your gRPC method uses the same request and response message type, you can use org.lognet.springboot.grpc.validation.group.RequestMessage and org.lognet.springboot.grpc.validation.group.ResponseMessage validation groups to apply different validation logic :

...
<getter name="someField">

            <!--should be empty for request message-->
            <constraint annotation="javax.validation.constraints.Size">
                <groups>
                    <value>org.lognet.springboot.grpc.validation.group.RequestMessage</value> (1)
                </groups>
                <element name="min">0</element>
                <element name="max">0</element>

            </constraint>

            <!--should NOT  be empty for response message-->
            <constraint annotation="javax.validation.constraints.NotEmpty">
                <groups>
                    <value>org.lognet.springboot.grpc.validation.group.ResponseMessage</value> (2)
                </groups>
            </constraint>
        </getter>
...
  1. Apply this constraint only for request message

  2. Apply this constraint only for response message

Note also custom cross-field constraint and its usage :

 <bean class="io.grpc.examples.GreeterOuterClass$Person">
        <class>
            <constraint annotation="org.lognet.springboot.grpc.demo.PersonConstraint"/>
        </class>
...

</bean>

As described in Interceptors ordering chapter, you can give validation interceptor the higher precedence than security interceptor and set grpc.security.auth.fail-fast property to false.
In 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.

By adding GRpcErrorHandler bean to your application, you get a chance to send your custom response headers. The error handler will be called with Status.INVALID_ARGUMENT and incoming request message that is failed.

6. GRPC response observer and Spring @Transactional caveats

While 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 :

class MyGrpcService extends ...{
    @Autowired
    private MyJpaRepository repo;

    @Transactional //(1)
    public void rpcCall(Req request, StreamOvserver<Res> observer) {
        Res response = // Database operations via repo
        observer.onNext(response); //(2)
        observer.onCompleted();
    }//(3)
}
  1. The method is annotated as @Transactional, Spring will commit the transaction at some time after methods returns

  2. Response is returned to the caller

  3. Methods returns, transaction eventually committed.

Theoretically, and as you can see - practically, there is small time-span when client (if the network latency is minimal, and your grpc server encouraged context switch right after <2>) can try to access the database via another grpc call before the transaction is committed.

The solution to overcome this situation is to externalize the transactional logic into separate service class :

@Service
class MyService{
    @Autowired
    private MyJpaRepository repo;

    @Transactional //(1)
    public Res doTransactionalWork(){
        // Database operations via repo
        return result;
    }//(2)
}
class MyGrpcService extends ...{
    @Autowired
    private MyService myService;

    public void rpcCall(Req request, StreamOvserver<Res> observer) {
        Res response = myService.doTransactionalWork();
        observer.onNext(response); //(3)
        observer.onCompleted();
    }
}
  1. Service method is transactional

  2. Transaction is eventually committed.

  3. Reply after transaction is committed.

By following this approach you also decouple the transport layer and business logic that now can be tested separately.

7. Spring Security Integration

7.1. Setup

Table 1. Dependencies to implement authentiction scheme (to be added to server-side project)
Scheme Dependencies

Basic

  • org.springframework.security:spring-security-config

Bearer

  • org.springframework.security:spring-security-config

  • org.springframework.security:spring-security-oauth2-jose

  • org.springframework.security:spring-security-oauth2-resource-server

Custom

  • org.springframework.security:spring-security-config

  • your.custom.lib

7.2. Server side configuration

GRPC security configuration follows the same principals and APIs as Spring WEB security configuration.

7.2.1. Default

GRPC security is enabled by default if you have org.springframework.security:spring-security-config dependency in your classpath.

This default configuration secures GRPC methods/services annotated with org.springframework.security.access.annotation.@Secured annotation.
Leaving value of the annotation empty (@Secured({})) means : authenticate only, no authorization will be performed.

If JwtDecoder bean exists in your context, it will also register JwtAuthenticationProvider to handle the validation of authentication claim.

BasicAuthSchemeSelector and BearerTokenAuthSchemeSelector are also automatically registered to support authentication with username/password and bearer token.

By setting grpc.security.auth.enabled to false, GRPC security can be turned-off.

7.2.2. Custom

Customization of GRPC security configuration is done by extending GrpcSecurityConfigurerAdapter (Various configuration examples and test scenarios are here.)

    @Configuration
    public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {
        @Autowired
        private JwtDecoder jwtDecoder;

        @Override
        public void configure(GrpcSecurity builder) throws Exception {

            builder.authorizeRequests()(1)
                    .methods(GreeterGrpc.getSayHelloMethod()).hasAnyAuthority("SCOPE_profile")(2)
            .and()
                    .authenticationProvider(JwtAuthProviderFactory.withAuthorities(jwtDecoder));(3)
        }
    }
  1. Get hold of authorization configuration object

  2. MethodDefinition of sayHello method is allowed for authenticated users with SCOPE_profile authority.

  3. Use JwtAuthenticationProvider to validate user claim (BEARER token) against resource server configured with spring.security.oauth2.resourceserver.jwt.issuer-uri property.

7.2.3. DIY

One is possible to plug in your own bespoke authentication provider by implementing AuthenticationSchemeSelector interface.

@Configuration
    public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {
    @Override
        public void configure(GrpcSecurity builder) throws Exception {
        builder.authorizeRequests()
                    .anyMethod().authenticated()(1)
                    .and()
                    .authenticationSchemeSelector(new AuthenticationSchemeSelector() { (2)
                            @Override
                            public Optional<Authentication> getAuthScheme(CharSequence authorization) {
                                return new MyAuthenticationObject(); (3)
                            }
                        })
                    .authenticationProvider(new AuthenticationProvider() { (4)
                        @Override
                        public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                            MyAuthenticationObject myAuth= (MyAuthenticationObject)authentication;
                            //validate myAuth
                            return MyValidatedAuthenticationObject(withAuthorities);(5)
                        }

                        @Override
                        public boolean supports(Class<?> authentication) {
                            return MyAuthenticationObject.class.isInstance(authentication);
                        }
                    });
 }
 }
  1. Secure all services methods.

  2. Register your own AuthenticationSchemeSelector.

  3. Based on provided authorization header - return Authentication object as a claim (not authenticated yet)

  4. Register your own AuthenticationProvider that supports validation of MyAuthenticationObject

  5. Validate provided authentication and return validated and authenticated Authentication object

AuthenticationSchemeSelector can also be registered by defining Spring bean in your application context:

@Bean
public AuthenticationSchemeSelector myCustomSchemeSelector(){
     return authHeader->{
         // your logic here
     };
}

Client side configuration support section explains how to pass custom authorization scheme and claim from GRPC client.

7.3. Obtaining Authentication details

To obtain Authentication object in the implementation of secured method, please use below snippet

final Authentication auth = GrpcSecurity.AUTHENTICATION_CONTEXT_KEY.get();

7.4. Custom authentication failure handling

By adding GRpcErrorHandler bean to your application, you get a chance to provide your custom response headers. The error handler will be called with Status.PERMISSION_DENIED/Status.UNAUTHENTICATED (and incoming request message , if you set grpc.security.auth.fail-fast property to false).
The demo is here

7.5. Client side configuration support

By 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 :

Per-channel
class MyClient{
    public void doWork(){
        final AuthClientInterceptor clientInterceptor = new AuthClientInterceptor((1)
                AuthHeader.builder()
                    .bearer()
                    .binaryFormat(true)(3)
                    .tokenSupplier(this::generateToken)(4)
        );

        Channel authenticatedChannel = ClientInterceptors.intercept(
                ManagedChannelBuilder.forAddress("host", 6565), clientInterceptor (2)
        );
        // use authenticatedChannel to invoke GRPC service
    }

     private ByteBuffer generateToken(){ (4)
         // generate bearer token against your resource server
     }
 }
  1. Create client interceptor

  2. Intercept channel

  3. Turn the binary format on/off:

    • When true, the authentication header is sent with Authentication-bin key using binary marshaller.

    • When false, the authentication header is sent with Authentication key using ASCII marshaller.

  1. Provide token generator function (Please refer to for example.)

    Per-call
    class MyClient{
        public void doWork(){
            AuthCallCredentials callCredentials = new AuthCallCredentials( (1)
                    AuthHeader.builder().basic("user","pwd".getBytes())
            );
    
            final SecuredGreeterGrpc.SecuredGreeterBlockingStub securedFutureStub = SecuredGreeterGrpc.newBlockingStub(ManagedChannelBuilder.forAddress("host", 6565));(2)
    
            final String reply = securedFutureStub
                    .withCallCredentials(callCredentials)(3)
                    .sayAuthHello(Empty.getDefaultInstance()).getMessage();
    
        }
     }
  2. Create call credentials with basic scheme

  3. Create service stub

  4. Attach call credentials to the call

    AuthHeader could also be built with bespoke authorization scheme :

     AuthHeader
       .builder()
       .authScheme("myCustomAuthScheme")
       .tokenSupplier(()->generateMyCustomToken())

8. Consul Integration

Starting 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 spring.cloud.service-registry.auto-registration.enabled is NOT set to false.

The 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.

Setting spring.cloud.consul.discovery.register-health-check to true will register GRPC health check service in Consul.

Tags could be set by defining spring.cloud.consul.discovery.tags property.

You can find the test that demonstrates the feature here.

9. Eureka Integration

When 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.
You will then add this project as compile dependency to your gRPC client and gRPC server projects.

To integrate Eureka simply follow the great guide from Spring.

Below are the essential parts of configurations for both server and client projects.

9.1. gRPC Server Project

  • Add eureka starter as dependency of your server project together with generated classes from proto files:

build.gradle
 dependencies {
     compile('org.springframework.cloud:spring-cloud-starter-eureka')
     compile project(":yourProject-api")
 }
  • Configure gRPC server to register itself with Eureka.

    bootstrap.yaml
    spring:
        application:
            name: my-service-name (1)
    1. Eureka’s ServiceId by default is the spring application name, provide it before the service registers itself with Eureka.

    application.yaml
    grpc:
        port: 6565 (1)
    eureka:
        instance:
            nonSecurePort: ${grpc.port} (2)
        client:
            serviceUrl:
                defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ (3)
    1. Specify the port number the gRPC is listening on.

    2. Register the eureka service port to be the same as grpc.port so client will know where to send the requests to.

    3. Specify the registry URL, so the service will register itself with.

  • Expose the gRPC service as part of Spring Boot Application.

    EurekaGrpcServiceApp.java
     @SpringBootApplication
     @EnableEurekaClient
     public class EurekaGrpcServiceApp {
    
         @GRpcService
         public static class GreeterService extends GreeterGrpc.GreeterImplBase {
             @Override
             public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
    
             }
         }
    
         public static void main(String[] args) {
             SpringApplication.run(DemoApp.class,args);
         }
     }

9.2. gRPC Client Project

  • Add eureka starter as dependency of your client project together with generated classes from proto files:

build.gradle
 dependencies {
     compile('org.springframework.cloud:spring-cloud-starter-eureka')
     compile project(":yourProject-api")
 }
  • Configure client to find the eureka service registry:

application.yaml
eureka:
  client:
    register-with-eureka: false (1)
    service-url:
      defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ (2)
  1. false if this project is not meant to act as a service to another client.

  2. Specify the registry URL, so this client will know where to look up the required service.

GreeterServiceConsumerApplication.java
@EnableEurekaClient
@SpringBootApplication
public class GreeterServiceConsumerApplication {
 public static void main(String[] args) {
   SpringApplication.run(GreeterServiceConsumerApplication.class, args);
 }
}
  • Use EurekaClient to get the coordinates of gRPC service instance from Eureka and consume the service :

GreeterServiceConsumer.java
@EnableEurekaClient
@Component
public class GreeterServiceConsumer {
    @Autowired
    private EurekaClient client;

    public void greet(String name) {
        final InstanceInfo instanceInfo = client.getNextServerFromEureka("my-service-name", false);(1)
        final ManagedChannel channel = ManagedChannelBuilder.forAddress(instanceInfo.getIPAddr(), instanceInfo.getPort())
                .usePlaintext()
                .build(); (2)
        final GreeterServiceGrpc.GreeterServiceFutureStub stub = GreeterServiceGrpc.newFutureStub(channel); (3)
        stub.greet(name); (4)

    }
}
  1. Get the information about the my-service-name instance.

  2. Build channel accordingly.

  3. Create stub using the channel.

  4. Invoke the service.

10. License

Apache 2.0

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

暂无描述 展开 收起
README
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

语言

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/leanring/grpc-spring-boot-starter.git
git@gitee.com:leanring/grpc-spring-boot-starter.git
leanring
grpc-spring-boot-starter
grpc-spring-boot-starter
master

搜索帮助