java grpc rmi_grpc使用分析

这里为了探索grpc的使用方法,简单的假设工程有服务提供方和服务调用方,并且服务提供方简单的暴露一个SayHello的接口给服务调用方消费。项目划分如下

core-knowledge-rpc- 定义协议明细,接口实现

core-knowledge-rpc-callee- 服务提供方

core-knowledge-rpc-caller- 服务消费方

1 定义协议明细

core-knowlege-rpc负责定义协议明细和接口实现,工程目录结构如下

在工程中创建源文件目录src/main/proto目录存放.proto协议文件。

定义协议

这里定义了一个helloworld.proto文件,内容如下

syntax="proto3";

option java_multiple_files = true;

option java_package = "org.core.knowledge.delivery.grpc";

option java_outer_classname = "HelloWorldProto";

option objc_class_prefix = "HLW";

package helloworld;

service Greeter {

rpc SayHello(HelloRequest) returns (HelloReply) {}

}

message HelloRequest {

string name = 1;

}

message HelloReply {

string message = 1;

}

文件第一句注明文件使用proto3的语法。协议中定义了一个Greeter服务,暴露SayHello接口,接收HelloRequest类型的输入,返回HelloReply类型的输出。HelloRequest类型携带了一个name的字符串信息;HelloReply类型返回一个message的字符串。

引入grpc依赖

这里grpc依赖netty网络通讯,pom依赖如下

UTF-8

1.25.0

junit

junit

4.10

test

io.grpc

grpc-netty-shaded

${grpc.version}

io.grpc

grpc-protobuf

${grpc.version}

io.grpc

grpc-stub

${grpc.version}

kr.motd.maven

os-maven-plugin

1.6.2

org.apache.maven.plugins

maven-compiler-plugin

1.8

1.8

UTF8

org.xolstice.maven.plugins

protobuf-maven-plugin

0.6.1

com.google.protobuf:protoc:3.10.0:exe:${os.detected.classifier}

grpc-java

io.grpc:protoc-gen-grpc-java:1.25.0:exe:${os.detected.classifier}

compile

compile-custom

这里引入grpc的版本为1.25.0,依赖的netty打包到了grpc-netty-shaded库中。接着,执行mvn compile命令生成服务源码。在工程目录结构中,target/generated-sources/protobuf/java和target/generated-sources/protobuf/grpc-java目录即为自动protoc工具自动生成的服务源文件。

实现Greeter接口

这里简单的将接收到的name字符串之前增加hello字符串返回,实现如下

GreeterImpl.java

public class GreeterImpl extends GreeterGrpc.GreeterImplBase{

@Override

public void sayHello(HelloRequest request, StreamObserver responseObserver) {

HelloReply reply = HelloReply.newBuilder().setMessage("Hello "+request.getName()).build();

responseObserver.onNext(reply);

responseObserver.onCompleted();

}

}

2 服务提供方实现

core-knowledge-rpc-callee是服务提供方,依赖grpc将Greeter服务暴露到网络中。服务提供方主要依赖grpc库的api接口启动一个服务端ServerSocket,同时将服务实现GreeterImpl注册到grpc。详细实现如下

HelloWorldCallee.java

public class HelloWorldCallee {

private Server server;

private void start() throws IOException {

int port = 50051;

server = ServerBuilder.forPort(port)

.addService(new GreeterImpl()).build().start();

Runtime.getRuntime().addShutdownHook(new Thread() {

@Override

public void run() {

System.err.println("*** shutting down gRPC server since JVM is shutting down");

HelloWorldCallee.this.stop();

System.err.println("*** server shut down");

}

});

}

private void stop() {

if(server != null) {

server.shutdown();

}

}

private void blockUntilShutdown() throws InterruptedException {

if(server != null) {

server.awaitTermination();

}

}

public static void main(String[] args) throws InterruptedException, IOException {

HelloWorldCallee server = new HelloWorldCallee();

server.start();

server.blockUntilShutdown();

}

}

grpc提供ServerBuilder类构件Server并注册服务。当然,需要将服务实现引入到项目中,

${project.groupId}

core-knowledge-rpc

${project.version}

groupId和version值与服务提供方相同。

3 服务消费方实现

服务消费方只需要借助grpc的ManagedChannelBuilder.build()构件网络连接通道ManagedChannel;然后使用ManagedChannel构建GreeterBlockingStub实例即可调用远程服务sayHello方法。实现代码如下

public class HelloWorldCaller {

private ManagedChannel channel;

private GreeterGrpc.GreeterBlockingStub blockingStub;

public HelloWorldCaller(String host,int port) {

this(ManagedChannelBuilder.forAddress(host, port)

.usePlaintext().build());

}

HelloWorldCaller(ManagedChannel channel){

this.channel = channel;

this.blockingStub = GreeterGrpc.newBlockingStub(channel);

}

public void shutdown() throws InterruptedException {

this.channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);

}

public void greet(String name) {

HelloRequest request = HelloRequest.newBuilder().setName(name).build();

HelloReply response;

try {

response = this.blockingStub.sayHello(request);

} catch (StatusRuntimeException e) {

System.err.println(e.getMessage());

return ;

}

System.out.println("Greeting: "+response.getMessage());

}

public static void main(String[] args) throws InterruptedException {

HelloWorldCaller caller = new HelloWorldCaller("localhost", 50051);

@SuppressWarnings("resource")

Scanner scanner = new Scanner(System.in);

try {

for(;;) {

System.out.print("please input message:");

String str = scanner.nextLine();

if("quit".equals(str)) break;

caller.greet(str);

}

}finally {

caller.shutdown();

}

}

}

main函数中,获取标准输入流中输入的字符串,作为远程服务的输入参数实现远程调用。调用结果如下

服务输入日志如下

16:37:33.332 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xdab71016, L:/127.0.0.1:50051 - R:/127.0.0.1:62749] INBOUND HEADERS: streamId=7 headers=GrpcHttp2RequestHeaders[:path: /helloworld.Greeter/SayHello, :authority: localhost:50051, :method: POST, :scheme: http, te: trailers, content-type: application/grpc, user-agent: grpc-java-netty/1.25.0, grpc-accept-encoding: gzip] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false

16:37:33.333 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xdab71016, L:/127.0.0.1:50051 - R:/127.0.0.1:62749] INBOUND DATA: streamId=7 padding=0 endStream=true length=19 bytes=000000000e0a0c41726520796f75206f6b203f

16:37:33.335 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xdab71016, L:/127.0.0.1:50051 - R:/127.0.0.1:62749] OUTBOUND HEADERS: streamId=7 headers=GrpcHttp2OutboundHeaders[:status: 200, content-type: application/grpc, grpc-encoding: identity, grpc-accept-encoding: gzip] streamDependency=0 weight=16 exclusive=false padding=0 endStream=false

16:37:33.340 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xdab71016, L:/127.0.0.1:50051 - R:/127.0.0.1:62749] OUTBOUND DATA: streamId=7 padding=0 endStream=false length=25 bytes=00000000140a1248656c6c6f2041726520796f75206f6b203f

16:37:33.341 [grpc-nio-worker-ELG-3-1] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xdab71016, L:/127.0.0.1:50051 - R:/127.0.0.1:62749] OUTBOUND HEADERS: streamId=7 headers=GrpcHttp2OutboundHeaders[grpc-status: 0] streamDependency=0 weight=16 exclusive=false padding=0 endStream=true

上面的示例显然: grpc很方便使用。可能你会问: 市面上已经存在很多的RPC框架,诸如JDK提供的RMI,基于HTTP协议二进制传输的Hessian,基于HTTP协议xml传输的Burlap及国产基于TCP协议的dubbo等,为毛还要使用grpc?RMI实现冗杂,Hessian和Burlap效率略低,dubbo加入了太多的业务属性不够单纯,grpc够单纯(连与spring集成的库都没有)够高效(依赖netty4+protobuffer)。选择grpc,为了代码优雅,你也就选择一片技术略高地。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值