package com.oy.model; public class User { private Integer id; private String name; private Integer age; private Double salary; }
package com.oy.model; public class Book { private Integer id; private String name; private Double price; }
service接口:html
package com.oy.service; import com.oy.model.User; public interface UserService { User getUserById(Integer id); }
package com.oy.service; import com.oy.model.Book; public interface BookService { int addBook(Book book); }
service實現類:java
package com.oy.service.impl; import org.springframework.stereotype.Service; import com.oy.model.User; import com.oy.service.UserService; @Service public class UserServiceImpl implements UserService { @Override public User getUserById(Integer id) { User user = null; if (id.equals(1)) { user = new User(); user.setAge(25); user.setId(1); user.setName("張無忌"); user.setSalary(10000.0); } else { user = new User(); user.setAge(20); user.setId(2); user.setName("周芷若"); user.setSalary(10000.0); } return user; } }
package com.oy.service.impl; import org.springframework.stereotype.Service; import com.oy.model.Book; import com.oy.service.BookService; @Service public class BookServiceImpl implements BookService{ @Override public int addBook(Book book) { return 1; } }
syntax = "proto3"; option java_multiple_files = false; option java_package = "com.oy.grpc"; option java_outer_classname = "GrpcLib"; //option objc_class_prefix = "HLW"; package grpc; // The service definition. service UserService { rpc getUserById (getUserByIdRequest) returns (GrpcReply) {} } service BookService { rpc addBook (addBookRequest) returns (GrpcReply) {} } /************************************************************/ message GrpcReply { int32 code = 1; string data = 2; } message getUserByIdRequest { int32 id = 1; } message addBookRequest { int32 id = 1; string name = 2; double price = 3; }
hello.proto定義了服務的方法名、入參和返回值。經過hello.proto能夠生成咱們須要的代碼,可是首先要在項目grpc007_proto的pom.xml中引入依賴和編譯插件:git
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.oy</groupId> <artifactId>grpc007_proto</artifactId> <version>0.0.1</version> <name>grpc007_proto</name> <description>grpc007_proto for Spring Boot</description> <properties> <java.version>1.8</java.version> <grpc.version>1.14.0</grpc.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.5.1:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.14.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
選中項目grpc007_proto,右鍵/Run As/Maven build...,輸入clean compile命令進行編譯。github
選中項目,使用F5更新項目,能夠看到生成的代碼以下:spring
2.四、發佈服務shell
儘管咱們定義了服務,可是客戶端並不能直接使用,咱們還須要在服務端對服務進一步包裝處理,而後才能發佈服務。apache
首先將項目grpc007_proto生成的3個類複製到 grpc007_server。而後要將咱們想要調用的方法進行包裝。json
pom.xml文件:c#
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.oy</groupId> <artifactId>grpc007_server</artifactId> <version>0.0.1</version> <name>grpc007_server</name> <description>grpc007_server for Spring Boot</description> <properties> <java.version>1.8</java.version> <grpc.version>1.14.0</grpc.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
UserGrpc類:(最好命名爲UserServiceImpl)springboot
package com.oy.service.grpc; import javax.annotation.Resource; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import com.oy.grpc.UserServiceGrpc; import com.oy.grpc.GrpcLib.GrpcReply; import com.oy.grpc.GrpcLib.getUserByIdRequest; import com.oy.model.User; import com.oy.service.UserService; import com.oy.utils.Utils; import io.grpc.stub.StreamObserver; @Component public class UserGrpc extends UserServiceGrpc.UserServiceImplBase { @Resource private UserService userService; @Override public void getUserById(getUserByIdRequest request, StreamObserver<GrpcReply> responseObserver) { Utils.log.info("UserGrpc#getUserById, id:{}", request.getId()); // 調用service層的方法 User user = userService.getUserById(request.getId()); String data = JSONObject.toJSONString(user); GrpcReply reply = GrpcReply.newBuilder().setCode(0).setData(data).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }
BookGrpc類:(最好命名爲BookServiceImpl)
package com.oy.service.grpc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import com.oy.grpc.BookServiceGrpc; import com.oy.grpc.GrpcLib.GrpcReply; import com.oy.grpc.GrpcLib.addBookRequest; import com.oy.model.Book; import com.oy.service.BookService; import com.oy.utils.Utils; import io.grpc.stub.StreamObserver; @Component public class BookGrpc extends BookServiceGrpc.BookServiceImplBase { @Autowired private BookService bookService; @Override public void addBook(addBookRequest request, StreamObserver<GrpcReply> responseObserver) { Integer id = request.getId(); String name = request.getName(); Double price = request.getPrice(); Utils.log.info("BookGrpc#addBook, id:{}, name:{}, price:{}", id, name, price); // 調用service層的方法 Book book = new Book(); book.setId(id); book.setName(name); book.setPrice(price); int result = bookService.addBook(book); JSONObject jsonObj = new JSONObject(); if (result == 1) { jsonObj.put("msg", "add book succ"); } else { jsonObj.put("msg", "add book failed"); } String data = jsonObj.toJSONString(); GrpcReply reply = GrpcReply.newBuilder().setCode(0).setData(data).build(); responseObserver.onNext(reply); // onCompleted() method to specify that we’ve finished dealing with the RPC responseObserver.onCompleted(); } }
定義grpc服務端,GrpcServer類:
package com.oy; import java.io.IOException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.oy.service.grpc.BookGrpc; import com.oy.service.grpc.UserGrpc; import com.oy.utils.Utils; import io.grpc.Server; import io.grpc.ServerBuilder; @Component public class GrpcServer { private int port = 23333; private Server server; @Autowired private UserGrpc userGrpc; @Autowired private BookGrpc bookGrpc; private void start() throws IOException { server = ServerBuilder.forPort(port) .addService(userGrpc) .addService(bookGrpc) .build().start(); Utils.log.info(("grpc service start...")); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { Utils.log.error(("shutting down gRPC server since JVM is shutting down")); GrpcServer.this.stop(); Utils.log.error("gRPC server shut down"); } }); } private void stop() { if (server != null) { server.shutdown(); } } // block private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } public void init(String[] args) throws IOException, InterruptedException { start(); blockUntilShutdown(); } }
springboot啓動類,實現CommandLineRunner接口,重寫run()方法。spring容器加載完畢後會調用run()方法,從而啓動grpc服務。能夠經過springboot啓動類的main方法啓動grpc007_server,也能夠將項目grpc007_server打成可執行jar再運行。
package com.oy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Grpc007ServerMainApplication implements CommandLineRunner { public static void main(String[] args) throws Exception { SpringApplication.run(Grpc007ServerMainApplication.class, args); } @Autowired private GrpcServer grpcServer; @Override public void run(String... args) throws Exception { grpcServer.init(args); } }
將項目grpc007_server打成可執行jar:選中項目 grpc007_proto,右鍵/Run As/Maven build...,輸入clean package命令進行打包,進入 項目grpc007_proto的target目錄,能夠將jar包重命名爲a.jar,shift+右鍵,在此處打開Powershell窗口。輸入java -jar a.jar,回車。 輸入clean package命令進行打包若是報錯,多是由於src/test/java裏面代碼的問題,刪除src/test/java裏面的內容。
客戶端程序,GrpcClient類:
package com.oy.grpc.client; import java.lang.reflect.Method; import java.util.concurrent.TimeUnit; import com.oy.grpc.BookServiceGrpc; import com.oy.grpc.GrpcClientPool; import com.oy.grpc.GrpcLib.GrpcReply; import com.oy.grpc.GrpcLib.addBookRequest; import com.oy.grpc.GrpcLib.getUserByIdRequest; import com.oy.grpc.UserServiceGrpc; import com.oy.utils.UtilFunctions; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; public class GrpcClient { public static String host = "localhost"; private final ManagedChannel channel; private final UserServiceGrpc.UserServiceBlockingStub userBlockingStub; private final BookServiceGrpc.BookServiceBlockingStub bookBlockingStub; public GrpcClient(String host, int port) { channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); userBlockingStub = UserServiceGrpc.newBlockingStub(channel); bookBlockingStub = BookServiceGrpc.newBlockingStub(channel); } public void shutdown() throws InterruptedException { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } @SuppressWarnings({ "rawtypes" }) public static Object call(String rpcMethoddName, Object... args) throws Exception { UtilFunctions.log.info("=========== GrpcClient#call begin ==========="); GrpcClient client = null; try { // client = GrpcClientPool.borrowObject(); client = new GrpcClient(host, 23333); Class[] argsTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { UtilFunctions.log.info("args types: {}", args[i].getClass()); argsTypes[i] = args[i].getClass(); } Method method = client.getClass().getMethod(rpcMethoddName, argsTypes); Object result = method.invoke(client, args); return result; } catch (Exception e) { UtilFunctions.log.error("GrpcClient#call Exception: {}", e.toString()); return null; } finally { if (client != null) { // GrpcClientPool.returnObject(client); client.shutdown(); } } } // ============= User module ============= public Object getUserById(Integer id) { UtilFunctions.log.info("=========== GrpcClient#getUserById begin ==========="); getUserByIdRequest request = getUserByIdRequest.newBuilder().setId(id).build(); GrpcReply response; try { response = userBlockingStub.getUserById(request); UtilFunctions.log.info("GrpcClient#getUserById response, code:{}, data:{}", response.getCode(), response.getData()); } catch (StatusRuntimeException e) { UtilFunctions.log.error("GrpcClient#getUserById error, StatusRuntimeException:{}", e); return null; } return response; } // ============= Book module ============= public Object addBook(Integer id, String name, Double price) { UtilFunctions.log.info("=========== GrpcClient#addBook begin ==========="); addBookRequest request = addBookRequest.newBuilder().setId(id).setName(name).setPrice(price).build(); GrpcReply response; try { response = bookBlockingStub.addBook(request); UtilFunctions.log.info("GrpcClient#addBook response, code:{}, data:{}", response.getCode(), response.getData()); } catch (StatusRuntimeException e) { UtilFunctions.log.error("GrpcClient#addBook error, StatusRuntimeException:{}", e); return null; } return response; } }
測試類:
package com.oy.grpc.client; import com.oy.grpc.GrpcLib.GrpcReply; import com.oy.utils.UtilFunctions; public class TestService { public static void main(String[] args) throws Exception { for (int i = 0; i < 1; i++) { new Thread(new Runnable() { @Override public void run() { GrpcReply result = null; try { //result = (GrpcReply) GrpcClient.call("getUserById", Integer.valueOf("1")); //result = (GrpcReply) GrpcClient.call("getUserById", 2); result = (GrpcReply) GrpcClient.call("addBook", 1, "thinking in java", 50.0); } catch (Exception e) { e.printStackTrace(); } UtilFunctions.log.info("client call interface, get code:{}, data:{}", result.getCode(), result.getData()); } }).start(); } } }