rpc服务搭建Java,gRPC构建RPC服务

本文介绍如何使用Grpc来否件和发布RPC服务,本文在最后附上github地址。

1.下载&安装 java版本的protoc,下载地址

我这里使用的是3.3.0版本,如图所示

46699d2f001f?from=singlemessage

protoc-version.png

选择一个属于你的平台protoc来安装,安装很简单,只需要将下载好的protoc的zip包解压到指定目录即可。

2.创建maven工程

选择一款你喜欢的编译器创建一个maven工程,maven工程创建好之后,在其工程的根目录下的pom文件中添加如下内容:

pom.xml文件内容:

1.6.1

1.8

3.3.0

1.5.0.Final

io.grpc

grpc-netty

${grpc.version}

io.grpc

grpc-protobuf

${grpc.version}

io.grpc

grpc-stub

${grpc.version}

kr.motd.maven

os-maven-plugin

${kr.motd.version}

org.xolstice.maven.plugins

protobuf-maven-plugin

0.5.0

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

grpc-java

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

src/main/proto

/Volumes/NETAC/soft/dev/protoc/bin/protoc

compile

compile-custom

org.apache.maven.plugins

maven-compiler-plugin

${jdk.version}

${jdk.version}

3.创建proto规则文件

在工程目录下的src/main下创建proto规则文件目录,目录结构如图所示:

46699d2f001f?from=singlemessage

proto_dir.png

3.1.创建规则文件

在这里我的proto规则文件中分别定义了Account和Greeter两个服务接口。

Greeter服务接口中定义了SayHello一个方法。

在Greeter服务中的方法只是简单的打招呼方法。

Account服务接口中定义了addAccount和getAccoutByName两个方法。

在Account服务中的这两个方法功能是模拟添加和查询账户。

3.1.1.定义服务

在创建好的proto目录下创建hello_account.proto规则文件,用于定义rpc服务,内容如下:

//使用proto3语法

syntax = "proto3";

//指定proto文件包名

package org.cooze.grpc.service;

//指定 java 包名

option java_package = "org.cooze.grpc.service";

//指定proto文件生成java文件后的类名

option java_outer_classname = "ServiceProto";

//开启多文件

option java_multiple_files = true;

//倒入指定的.proto文件

import "entity/req_res.proto";

//定义rpc服务接口

service Greeter {

//服务端接口方法

rpc SayHello (org.cooze.grpc.entity.HelloRequest) returns (org.cooze.grpc.entity.HelloReply);

}

//定义rpc服务接口

service Account {

rpc addAccount(org.cooze.grpc.entity.Account) returns (org.cooze.grpc.entity.AccountResponse);

rpc getAccoutByName(org.cooze.grpc.entity.Account) returns (org.cooze.grpc.entity.AccountResponse);

}

3.1.2.定义消息

在proto目录下的子目录entity中创建req_res.proto文件,用于定义rpc的消息类型,内容如下:

//使用proto3语法

syntax = "proto3";

//指定proto文件包名

package org.cooze.grpc.entity;

//指定 java 包名

option java_package = "org.cooze.grpc.entity";

//指定proto文件生成java文件后的类名

option java_outer_classname = "EntityProto";

//开启多文件

option java_multiple_files = true;

//请求参数

message HelloRequest {

string name = 1;

}

//响应参数

message HelloReply {

string message = 1;

}

message Account {

string name = 1;

string sex = 2;

int32 age = 3;

}

message AccountResponse {

string msg = 1;

int32 code = 2;

repeated Account results = 3;

}

proto3定义服务和消息,请参看我翻译的《gRPC之proto语法》,翻译难免带有个人主观色彩,请见谅.

3.2.编译proto文件

在创建好proto文件,并定义好消息类型和服务之后,结下来就是编译proto规则文件生成对应的java代码。

打开命令终端并切换到工程根目录下

我这里使用的编译器是idea编译器,所以打开终端很简单-_-!,终端打开后键入命令mvn compile编译即可,如图 :

46699d2f001f?from=singlemessage

compile.png

在执行完比那一命令之后,在工程根目录下会生成的target,而target目录的结构以及java类文件,如下图所示:

46699d2f001f?from=singlemessage

generator_code.png

其中,生成的服务定义接口类为:AccountGrpc和GreeterGrpc,消息类型类为:Account、AccountResponse、HelloReply、HelloRequest。

4.Grpc服务和客户端实现

完成编辑proto规则文件和生成对应待grpc代码之后,就可以开始实现Grpc的服务端代码和客户端代码了。

创建java包结构和文件,如图所示:

46699d2f001f?from=singlemessage

create_package.png

4.1.Grpc服务端业务实现代码

不多说啥了,代码里有注释,所以上代码!

GreeterImpl.java代码如下:

public class GreeterImpl extends GreeterGrpc.GreeterImplBase {

@Override

public void sayHello(HelloRequest req, StreamObserver responseObserver) {

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

//处理接收到的消息

String msg = reply.getMessage();

System.out.println("服务端收到消息:" + msg);

//响应消息

HelloReply response = reply.toBuilder().setMessage("世界你好!").build();

responseObserver.onNext(response);

responseObserver.onCompleted();

}

}

AccountImpl.java代码如下:

public class AccountImpl extends AccountGrpc.AccountImplBase {

@Override

public void addAccount(Account request, StreamObserver responseObserver) {

//处理请求参数

System.out.println(StringFormatter.format("新增用户:%s\n性别:%s\n年龄:%d岁", request.getName(), request.getSex(), request.getAge()).get());

//处理响应参数

AccountResponse response = AccountResponse.getDefaultInstance().toBuilder()

.setCode(10000)

.setMsg("success!").build();

responseObserver.onNext(response);

responseObserver.onCompleted();

}

@Override

public void getAccoutByName(Account request, StreamObserver responseObserver) {

//处理请求参数

System.out.println(StringFormatter.format("请求查询用户名:%s", request.getName()).get());

//处理响应参数

List list = new ArrayList<>();

Account account1 = Account.getDefaultInstance().toBuilder()

.setName("张三")

.setAge(20)

.setSex("男").build();

list.add(account1);

Account account2 = Account.getDefaultInstance().toBuilder()

.setAge(30)

.setSex("男")

.setName("李四").build();

list.add(account2);

AccountResponse response = AccountResponse.getDefaultInstance().toBuilder()

.setCode(10000)

.setMsg("success!")

.addAllResults(list)

.build();

responseObserver.onNext(response);

responseObserver.onCompleted();

}

}

4.2.Grpc客户端代码

不多说啥了,代码里有注释,所以上代码!

BaseClient.java代码如下:

public class BaseClient {

private final ManagedChannel channel;

private final GreeterGrpc.GreeterBlockingStub greeterBlockingStub;

private final AccountGrpc.AccountBlockingStub accountBlockingStub;

private BaseClient(ManagedChannel channel) {

this.channel = channel;

this.greeterBlockingStub = GreeterGrpc.newBlockingStub(channel);

this.accountBlockingStub = AccountGrpc.newBlockingStub(channel);

}

/**

* 构造客户端与Greeter 服务端连接 {@code host:port}

*

* @param host 主机地址

* @param port 端口

*/

public BaseClient(String host, int port) {

this(ManagedChannelBuilder.forAddress(host, port)

// Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid

// needing certificates.

.usePlaintext(true)

.build());

}

/**

* 关闭函数

* @throws InterruptedException

*/

public void shutdown() throws InterruptedException {

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

}

public GreeterGrpc.GreeterBlockingStub getGreeterBlockingStub() {

return greeterBlockingStub;

}

public AccountGrpc.AccountBlockingStub getAccountBlockingStub() {

return accountBlockingStub;

}

}

GreeterClient.java代码如下:

public class GreeterClient {

private final GreeterGrpc.GreeterBlockingStub blockingStub;

public GreeterClient(BaseClient client) {

blockingStub = client.getGreeterBlockingStub();

}

public void greet(String name) {

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

HelloReply response;

try {

response = blockingStub.sayHello(request);

String msg = response.getMessage();

//接收到服务端返回的消息

System.out.println("客户端收到消息:" + msg);

} catch (StatusRuntimeException e) {

return;

}

}

}

AccountClient.java代码如下:

public class AccountClient {

private final AccountGrpc.AccountBlockingStub accountBlockingStub;

private final BaseClient client;

public AccountClient(BaseClient client) {

this.client = client;

this.accountBlockingStub = client.getAccountBlockingStub();

}

public void addAccount(String name, String sex, int age) {

Account account = Account.getDefaultInstance().toBuilder()

.setName(name)

.setSex(sex)

.setAge(age)

.build();

AccountResponse response = this.accountBlockingStub.addAccount(account);

System.out.println(StringFormatter.format("返回消息:%s\n状态:%d", response.getMsg(), response.getCode()).get());

}

public void queryAccout(String name) {

Account account = Account.getDefaultInstance().toBuilder()

.setName(name).build();

AccountResponse response = this.accountBlockingStub.getAccoutByName(account);

System.out.println(StringFormatter.format("返回消息:%s\n状态:%d", response.getMsg(), response.getCode()).getValue());

System.out.println("查询结果:");

List list = response.getResultsList();

for (Account acc : list) {

System.out.println(StringFormatter.format("姓名:%s,性别:%s,年龄:%d", acc.getName(), acc.getSex(), acc.getAge()).get());

}

}

}

4.3.Grpc服务端启动引导类代码

不多说啥了,代码里有注释,所以上代码!

rpc引导类BootStrap.java代码如下:

public class BootStrap {

private Server server;

/**

* 服务启动类

*

* @param port 端口

* @throws IOException

*/

private void start(int port) throws IOException {

server = ServerBuilder.forPort(port)

//注册服务

.addService(new GreeterImpl())

.addService(new AccountImpl())

.build()

.start();

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

@Override

public void run() {

System.err.println("*** JVM 关闭,导致gRPC服务关闭!");

BootStrap.this.stop();

System.err.println("*** 服务关闭");

}

});

}

/**

* RPC 服务关闭

*/

private void stop() {

if (server != null) {

server.shutdown();

}

}

/**

* 设置守护进程

*/

private void blockUntilShutdown() throws InterruptedException {

if (server != null) {

server.awaitTermination();

}

}

/**

* RPC服务启动main函数

*/

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

final BootStrap server = new BootStrap();

server.start(50051);

server.blockUntilShutdown();

}

}

4.3.Grpc测试

测试类代码如下:

public class Test {

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

BaseClient client = new BaseClient("localhost", 50051);

try {

System.out.println("===============GreeterClient============");

GreeterClient greeterClient = new GreeterClient(client);

greeterClient.greet("Hello");

System.out.println("===============AccountClient============");

AccountClient accountClient = new AccountClient(client);

System.out.println("===============新增============");

accountClient.addAccount("张飞", "男", 45);

System.out.println("===============查找============");

accountClient.queryAccout("测试");

} finally {

client.shutdown();

}

}

}

好了,所有的前序工作都做完了,开始测试了!

启动rpc引导类BootStrap.java

运行客户端测试类

服务端效果图如下:

46699d2f001f?from=singlemessage

server.png

客户端效果图如下:

46699d2f001f?from=singlemessage

client.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值