• 基于gRPC实现的rpc通讯框架


    grpc-example

    基于gRPC实现的简单rpc框架

    配置

    属性配置

    pom.xml中配置依赖的gRPC版本号

    	<properties>
    		<grpc.version>1.32.1</grpc.version>
    		<!-- Message源文件输出目录 -->
    		<javaOutputDirectory>${project.basedir}/src/main/java-proto</javaOutputDirectory>
    		<!-- gRPC源文件输出目录 -->
    		<protocPluginOutputDirectory>${project.basedir}/src/main/java-grpc</protocPluginOutputDirectory>
    	</properties>
    

    Maven依赖

    	<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.74</version>
    		</dependency>
    		<dependency>
    			<groupId>ch.qos.logback</groupId>
    			<artifactId>logback-classic</artifactId>
    			<version>1.2.3</version>
    		</dependency>
    
    	</dependencies>
    

    Maven插件

    	<build>
    		<extensions>
    			<extension>
    				<groupId>kr.motd.maven</groupId>
    				<artifactId>os-maven-plugin</artifactId>
    				<version>1.6.2</version>
    			</extension>
    		</extensions>
    		<plugins>
    			<plugin>
    				<groupId>org.xolstice.maven.plugins</groupId>
    				<artifactId>protobuf-maven-plugin</artifactId>
    				<version>0.6.1</version>
    				<configuration>
    					<protocArtifact>
    						com.google.protobuf:protoc:3.13.0:exe:${os.detected.classifier}
    					</protocArtifact>
    					<pluginId>grpc-java</pluginId>
    					<pluginArtifact>
    						io.grpc:protoc-gen-grpc-java:1.32.1:exe:${os.detected.classifier}
    					</pluginArtifact>
    				</configuration>
    				<executions>
    					<execution>
    						<goals>
    							<goal>compile</goal>
    							<goal>compile-custom</goal>
    						</goals>
    					</execution>
    				</executions>
    			</plugin>
    		</plugins>
    	</build>
    

    框架开发

    Protobuf文件

    创建文件 src/main/proto/crpc_protocol.proto

    syntax = "proto3";
    
    option java_package = "com.github.leeyazhou.grpc";
    option java_multiple_files = true;
    option java_outer_classname = "CrpcProtocol";
    
    message RequestGrpcMessage {
        bytes invocation = 1;
    }
    
    message ResponseGrpcMessage {
        bytes response = 1;
    }
    
    service MessageService {
        rpc request (RequestGrpcMessage) returns (ResponseGrpcMessage);
    }
    

    执行如下命令会生成Protobuf文件对应的Java类

    mvn protobuf:compile 
    mvn protobuf:compile-custom
    

    公用基础模型类

    Invocation.java

    package com.github.leeyazhou.grpc.core;
    
    public class Invocation {
    
    	private String serviceName;
    	private String methodName;
    	private Object[] args;
    
    	public String getServiceName() {
    		return serviceName;
    	}
    
    	public void setServiceName(String serviceName) {
    		this.serviceName = serviceName;
    	}
    
    	public String getMethodName() {
    		return methodName;
    	}
    
    	public void setMethodName(String methodName) {
    		this.methodName = methodName;
    	}
    
    	public Object[] getArgs() {
    		return args;
    	}
    
    	public void setArgs(Object[] args) {
    		this.args = args;
    	}
    
    	
    }
    
    

    Response.java

    package com.github.leeyazhou.grpc.core;
    
    public class Response {
    
    	private boolean error;
    	private Object response;
    	private Throwable exception;
    
    	public boolean isError() {
    		return error;
    	}
    
    	public void setError(boolean error) {
    		this.error = error;
    	}
    
    	public Object getResponse() {
    		return response;
    	}
    
    	public void setResponse(Object response) {
    		this.response = response;
    	}
    
    	public Throwable getException() {
    		return exception;
    	}
    
    	public void setException(Throwable exception) {
    		this.exception = exception;
    	}
    
    }
    
    

    Server代码

    GrpcServer.java

    package com.github.leeyazhou.grpc.core.server;
    
    import java.io.IOException;
    
    import io.grpc.Server;
    import io.grpc.ServerBuilder;
    
    public class GrpcServer {
    	private Server server;
    	private ServiceHandler serviceHandler;
    
    	public GrpcServer(int port) {
    		this.serviceHandler = new ServiceHandler();
    		this.server = ServerBuilder.forPort(port)
    				// 将具体实现的服务添加到gRPC服务中
    				.addService(new GrpcServerHandler(serviceHandler))
    
    				.build();
    	}
    
    	public GrpcServer addService(String name, Object service) {
    		serviceHandler.addService(name, service);
    		return this;
    	}
    
    	public void start() throws IOException {
    		server.start();
    	}
    
    	public void shutdown() {
    		server.shutdown();
    	}
    }
    

    GrpcServerHandler.java负责处理接收到的请求,并转发给ServiceHandler.java处理,处理完成后响应给请求端。

    package com.github.leeyazhou.grpc.core.server;
    
    import com.github.leeyazhou.grpc.MessageServiceGrpc.MessageServiceImplBase;
    import com.github.leeyazhou.grpc.core.Invocation;
    import com.github.leeyazhou.grpc.core.Response;
    import com.github.leeyazhou.grpc.core.serializer.JSONSerializer;
    import com.github.leeyazhou.grpc.core.serializer.Serializer;
    import com.github.leeyazhou.grpc.RequestGrpcMessage;
    import com.github.leeyazhou.grpc.ResponseGrpcMessage;
    import com.google.protobuf.ByteString;
    
    import io.grpc.stub.StreamObserver;
    
    public class GrpcServerHandler extends MessageServiceImplBase {
    	private ServiceHandler serviceHandler;
    	private Serializer serializer = new JSONSerializer();
    
    	public GrpcServerHandler(ServiceHandler serviceHandler) {
    		this.serviceHandler = serviceHandler;
    	}
    
    	@Override
    	public void request(RequestGrpcMessage request, StreamObserver<ResponseGrpcMessage> responseObserver) {
    		try {
    			final Invocation invocation = serializer.deserialize(request.getInvocation().toByteArray(),
    					Invocation.class);
    			final Response response = handleRequest(invocation);
    
    			byte[] jsonByte = serializer.serialize(response);
    			ResponseGrpcMessage resp = ResponseGrpcMessage.newBuilder().setResponse(ByteString.copyFrom(jsonByte))
    					.build();
    			responseObserver.onNext(resp);
    			responseObserver.onCompleted();
    		} catch (Exception e) {
    			responseObserver.onError(e);
    		}
    	}
    
    	private Response handleRequest(Invocation invocation) {
    		Response response = new Response();
    		response.setError(false);
    		try {
    			Object ret = serviceHandler.handle(invocation);
    			response.setResponse(ret);
    		} catch (Exception e) {
    			response.setError(true);
    			response.setException(e);
    		}
    		return response;
    	}
    }
    

    ServiceHandler.java

    package com.github.leeyazhou.grpc.core.server;
    
    import java.lang.reflect.Method;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.github.leeyazhou.grpc.core.Invocation;
    
    public class ServiceHandler {
    	private Map<String, Object> services = new ConcurrentHashMap<>();
    	private Map<String, Method> serviceMethods = new ConcurrentHashMap<>();
    
    	public Object handle(Invocation invocation) {
    		Object service = services.get(invocation.getServiceName());
    		Method serviceMethod = serviceMethods.get(invocation.getServiceName() + "$" + invocation.getMethodName());
    
    		try {
    			return serviceMethod.invoke(service, invocation.getArgs());
    		} catch (Exception e) {
    			e.printStackTrace();
    			throw new RuntimeException(e);
    		}
    	}
    
    	public void addService(String name, Object service) {
    		this.services.put(name, service);
    		Method[] methods = service.getClass().getDeclaredMethods();
    		if (methods != null) {
    			for (Method method : methods) {
    				String key = name + "$" + method.getName();
    				serviceMethods.put(key, method);
    			}
    		}
    
    	}
    }
    

    Client代码

    GrpcClient.java

    package com.github.leeyazhou.grpc.core.client;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.github.leeyazhou.grpc.MessageServiceGrpc;
    import com.github.leeyazhou.grpc.RequestGrpcMessage;
    import com.github.leeyazhou.grpc.ResponseGrpcMessage;
    import com.github.leeyazhou.grpc.core.Invocation;
    import com.github.leeyazhou.grpc.core.Response;
    import com.github.leeyazhou.grpc.core.serializer.JSONSerializer;
    import com.github.leeyazhou.grpc.core.serializer.Serializer;
    import com.google.protobuf.ByteString;
    
    import io.grpc.ManagedChannel;
    import io.grpc.ManagedChannelBuilder;
    
    public class GrpcClient {
    	private final Serializer serializer = new JSONSerializer();
    	private final MessageServiceGrpc.MessageServiceBlockingStub blockingStub;
    	private static final Map<String, GrpcClient> clientCache = new ConcurrentHashMap<>();
    
    	public static GrpcClient get(String host, int port) {
    		final String key = host + ":" + port;
    		return clientCache.compute(key, (k1, v1) -> {
    			return v1 != null ? v1 : new GrpcClient(host, port);
    		});
    	}
    
    	public GrpcClient(String host, int port) {
    		ManagedChannel managedChannel = ManagedChannelBuilder.forAddress(host, port)
    				// 使用非安全机制传输
    				.usePlaintext().build();
    		this.blockingStub = MessageServiceGrpc.newBlockingStub(managedChannel);
    	}
    
    	public Response request(Invocation invocation) {
    		byte[] jsonBytes = serializer.serialize(invocation);
    		ByteString byteString = ByteString.copyFrom(jsonBytes);
    
    		RequestGrpcMessage greeting = RequestGrpcMessage.newBuilder().setInvocation(byteString).build();
    		ResponseGrpcMessage resp = blockingStub.request(greeting);
    		byte[] responseByte = resp.getResponse().toByteArray();
    		return serializer.deserialize(responseByte, Response.class);
    	}
    }
    

    示例

    服务类开发

    EchoService.java定义服务接口

    public interface EchoService {
    	String echo(String echo);
    }
    

    EchoServiceImpl.java实现服务功能:

    public class EchoServiceImpl implements EchoService {
    	@Override
    	public String echo(String echo) {
    		System.err.println("回声: " + echo);
    		return echo;
    	}
    }
    

    启动服务端

    GrpcProvider.java 启动Server服务,并监听端口8000

    public class GrpcProvider {
    
    	public static void main(String[] args) throws Exception {
    		new GrpcProvider().start();
    		Thread.sleep(Integer.MAX_VALUE);
    	}
    
    	public void start() throws Exception {
    		int port = 8000;
    		GrpcServer server = new GrpcServer(port);
    		server.addService(EchoService.class.getSimpleName(), new EchoServiceImpl());
    		server.start();
    	}
    }
    

    客户端调用服务

    public class GrpcConsumer {
    
    	public static void main(String[] args) {
    		new GrpcConsumer().start();
    	}
    
    	public void start() {
    		String host = "127.0.0.1";
    		int port = 8000;
    		GrpcClient client = GrpcClient.get(host, port);
    
    		Invocation invocation = new Invocation();
    		invocation.setServiceName("EchoService");
    		invocation.setMethodName("echo");
    		invocation.setArgs(new String[] { "测试GRPC" });
    		Response response = client.request(invocation);
    		System.out.println(response.getResponse());
    	}
    }
    

    其他

    源码地址github.com/leeyazhou/grpc-example


    一介书生:关注多线程、高并发、分布式、微服务和系统架构。
  • 相关阅读:
    java异常
    集群、分布式、负载均衡区别
    基本数据结构的比较
    记录一次tomcat问题排查记录:org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19
    记录 Java 的 BlockingQueue 中的一些坑
    Java高级面试题解析(二):百度Java面试题前200页(精选)
    学习netty遇到的关于 LineBasedFrameDecoder 的问题
    ThreadPoolExecutor 入参 corePoolSize 和 maximumPoolSize 的联系
    TreeMap 的排序冲突吗
    checkbox jquery操作总结
  • 原文地址:https://www.cnblogs.com/leeyazhou/p/13804066.html
Copyright © 2020-2023  润新知