将 java grpc 服务打包为 jar 时收到“UNIMPLMENTED:找不到方法”

问题描述 投票:0回答:1

我有一个 grpc 服务,这里是代码摘录: 原型:

// proto/campus/graduate/v1/graduate.proto
syntax = 'proto3';

package wusthelper.campus.graduate.v1;

option java_package = 'cn.wustlinghang.wusthelper.rpc.graduate.v1';
option java_outer_classname = 'GraduateProto';
option java_generic_services = true;

service GraduateRequestAgent {
  // Login Login service for graduate
  rpc Login (UsernamePasswordReq) returns (AgentReply);
  // GetStudentInfo Get the student info
  rpc GetStudentInfo (CookieReq) returns (AgentReply);
  //... more
}

service GraduateParser {
  // ParseScores Parse the score page
  rpc ParseScores (PlainText) returns (ScoreParseReply);
  //... more
}

这是服务器实现:

  • GraduateRequestAgentImpl.java
package cn.wustlinghang.wusthelper.campus.graduate.service;
import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class GraduateRequestAgentImpl extends GraduateRequestAgentGrpc.GraduateRequestAgentImplBase {

    @Override
    public void login(CampusCommonProto.UsernamePasswordReq request,
                      StreamObserver<CampusCommonProto.AgentReply> responseObserver) {
        //...implements
    }

    //... other implements
}
  • GraduateParserImpl.java
package cn.wustlinghang.wusthelper.campus.graduate.service;

import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class GraduateParserImpl extends GraduateParserGrpc.GraduateParserImplBase {

    @Override
    public void parseScores(CommonProto.PlainText request,
                            StreamObserver<GraduateProto.ScoreParseReply> responseObserver) {
        // ...implements
    }
}

奇怪的是,当我在idea中启动服务器并调用

login()
ParseScores()
时,一切都如我所料。 但是当我将服务器项目打包成jar文件时,如果我调用
login()
等方法,我会收到
io.grpc.StatusRuntimeException: UNIMPLEMENTED: Method not found: wusthelper.campus.graduate.v1.GraduateRequestAgent/Login
异常。只有当我将服务器打包为jar文件时才会出现该问题。

如果我使用像

grpcurl
evans
这样的grpc调试工具,无论我将服务器打包为jar还是直接在idea中运行,它们都可以很好地工作,但我就是无法从客户端调用。 😰😫

客户端使用的生成的proto代码与服务器使用的相同,并且服务器日志显示它实际上加载了实现服务:

2023-04-06T20:23:37.358+08:00  INFO 27868 --- [           main] g.s.a.GrpcServerFactoryAutoConfiguration : Detected grpc-netty-shaded: Creating ShadedNettyGrpcServerFactory
2023-04-06T20:23:37.507+08:00  INFO 27868 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: wusthelper.campus.graduate.v1.GraduateParser, bean: graduateParserImpl, class: cn.wustlinghang.wusthelper.campus.graduate.service.GraduateParserImpl
2023-04-06T20:23:37.507+08:00  INFO 27868 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: wusthelper.campus.graduate.v1.GraduateRequestAgent, bean: graduateRequestAgentImpl, class: cn.wustlinghang.wusthelper.campus.graduate.service.GraduateRequestAgentImpl
2023-04-06T20:23:37.507+08:00  INFO 27868 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.health.v1.Health, bean: grpcHealthService, class: io.grpc.protobuf.services.HealthServiceImpl
2023-04-06T20:23:37.507+08:00  INFO 27868 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.reflection.v1alpha.ServerReflection, bean: protoReflectionService, class: io.grpc.protobuf.services.ProtoReflectionService
2023-04-06T20:23:37.632+08:00  INFO 27868 --- [           main] n.d.b.g.s.s.GrpcServerLifecycle          : gRPC Server started, listening on address: 0.0.0.0, port: 19090
2023-04-06T20:23:37.640+08:00  INFO 27868 --- [           main] c.w.w.c.graduate.GraduateServiceMain     : Started GraduateServiceMain in 1.024 seconds (process running for 1.417)

调试日志也和正常运行时一样。

即使我尝试用 Golang 重写客户端代码,也得到了相同的行为。

环境:

  • java 17
  • springboot 3.0.4
  • grpc-java 1.54.0
  • grpc-spring-boot-starter(net.devh)2.14.0.RELEASE

我也尝试过删除 springboot 和 grpc-starter 并将其重写为 prue grpc 服务,但没有用。😰

java jar grpc
1个回答
0
投票

好吧,我又遇到了这个问题,现在对我来说似乎有点傻😂。我已经弄清楚发生了什么事。主要是没有理解Maven内部Springboot项目中依赖的打包机制……

我希望这可以帮助您,或者在您束手无策时提供一些故障排除的想法。

这个项目的Maven模块结构如下(大致是这样,已经很久了,不太记得了,项目现在已经不再使用grpc了😂):

backend-project
  - common       // the common module that module 'services' and 'gateway' module depends, contains the proto file and protoc generated code
  - services     // services that implemented the grpc service, the grpc server
    - graduate   // the graduate service, where file 'GraduateRequestAgentImpl.java' in.
    - undergrad  // the undergrad service
    - library
    - ... and so on
  - web            // web service, for frontend
    - gateway      // the api gateway that will call the service rpc, the grpc client main

我的项目的顶级父级不是springboot父级,而是项目的根模块。也就是说,它不是任何模块的“子级”,它是父级,是下面所有模块的父级。

我更新了common的proto文件并重新生成了相应的Java proto代码文件,并在各自的服务器上实现了它们,但我没有执行mvn install操作。

后来我反编译了客户端和服务端的jar包,发现里面实际的公共模块代码是不一样的😥。在服务端的jar包中,生成的代码确实有新添加的部分,但是在客户端(网关模块)中,却出奇的没有😰。

我对公共模块执行mvm install操作后,一切都很好,双方都没有问题,一切正常。

但是为什么这在 IDEA 中不是问题呢?

IDEA中的‘运行命令’是这样的:

C:\Users\user\.jdks\graalvm-ce-17\bin\java.exe
  -classpath '
  C:\Users\user\projects\backend-project\common\target\classes;
  C:\Users\user\projects\backend-project\web\gateway\target\classes;
  C:\Users\user\.m2\repository\org\springframework\boot\spring-boot-starter-web\3.1.1\spring-boot-starter-web-3.1.1.jar;
  ... and many dependences
  C:\Users\user\.m2\repository\org\springframework\boot\spring-boot-starter\3.1.1\spring-boot-starter-3.1.1.jar;
  C:\Users\user\.m2\repository\org\springframework\boot\spring-boot-starter-logging\3.1.1\spring-boot-starter-logging-3.1.1.jar;'
  # the client main class
  wusthelper.WebBackendMain 

可以看到依赖项是通过指定所有依赖项的类路径来导入的,并且其他模块是从编译后的类文件中导入的。显然,那里的文件是新的。

将客户端打包为jar时,依赖项是从maven本地存储库导入的,而不是

target
文件夹。所以客户端仍在使用
common
模块的遗留代码。

这就是为什么我在公共模块中运行公共

mvn install
,问题解决了。

© www.soinside.com 2019 - 2024. All rights reserved.