├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── RPC-Framework.iml ├── pom.xml ├── readme.md ├── rpc-api ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── ncst │ └── api │ ├── ByeService.java │ ├── DataObject.java │ └── HelloService.java ├── rpc-common ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── ncst │ └── rpc │ ├── entity │ ├── RpcRequest.java │ └── RpcResponse.java │ ├── enumeration │ ├── PackageType.java │ ├── ResponseCode.java │ ├── RpcError.java │ └── SerializerCode.java │ ├── exception │ ├── RpcException.java │ └── SerializeException.java │ ├── factory │ ├── SingletonFactory.java │ └── ThreadPoolFactory.java │ └── util │ ├── NacosUtil.java │ ├── ReflectUtil.java │ └── RpcMessageChecker.java ├── rpc-core ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── ncst │ ├── annotation │ ├── Service.java │ └── ServiceScan.java │ ├── codec │ ├── CommoDecoder.java │ └── CommonEncoder.java │ ├── handler │ └── RequestHandler.java │ ├── hook │ └── ShutDownHook.java │ ├── loadbalancer │ ├── LoadBalancer.java │ ├── RandomLoadBalancer.java │ └── RoundRobinLoadBalancer.java │ ├── provider │ ├── ServiceProvider.java │ └── ServiceProviderImpl.java │ ├── registry │ ├── NacosServiceDiscovery.java │ ├── NacosServiceRegistry.java │ ├── ServiceDiscovery.java │ └── ServiceRegistry.java │ ├── serializer │ ├── CommonSerializer.java │ ├── HessianSerializer.java │ ├── JsonSerializer.java │ ├── KryoSerializer.java │ └── ProtobufSerializer.java │ └── transport │ ├── AbstractRpcServer.java │ ├── RpcClient.java │ ├── RpcClientProxy.java │ ├── RpcServer.java │ ├── client │ ├── ChannelProvider.java │ ├── NettyClient.java │ ├── NettyClientHandler.java │ └── UnprocessedRequests.java │ └── server │ ├── NettyServer.java │ └── NettyServerHandler.java ├── test-client ├── pom.xml └── src │ └── main │ └── java │ └── NettyTestClient.java └── test-server ├── pom.xml └── src └── main ├── java └── com │ └── ncst │ └── nettyserver │ ├── ByeServiceImpl.java │ ├── HelloServiceImpl.java │ └── NettyTestServer.java └── resources └── log4j.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /rpc-api/target/ 3 | /rpc-common/target/ 4 | /rpc-core/target/ 5 | /test-client/target/ 6 | /test-server/target/ -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /../../../../../:\java\idea\RPC-Framework\.idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /RPC-Framework.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.ncst 8 | RPC-Framework 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | rpc-api 13 | rpc-common 14 | rpc-core 15 | test-client 16 | test-server 17 | 18 | 19 | 20 | 21 | 1.8 22 | 1.8 23 | UTF-8 24 | 4.1.50.Final 25 | 29.0-jre 26 | 27 | 28 | 29 | 30 | io.netty 31 | netty-all 32 | ${netty-version} 33 | 34 | 35 | com.fasterxml.jackson.core 36 | jackson-core 37 | 2.11.0 38 | 39 | 40 | com.fasterxml.jackson.core 41 | jackson-databind 42 | 2.11.0 43 | 44 | 45 | com.fasterxml.jackson.core 46 | jackson-annotations 47 | 2.11.0 48 | 49 | 59 | 60 | org.projectlombok 61 | lombok 62 | 1.18.12 63 | 64 | 65 | org.slf4j 66 | slf4j-api 67 | 1.7.30 68 | 69 | 70 | org.slf4j 71 | slf4j-simple 72 | 1.7.25 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 循序渐进写RPC 2 | 3 | ## 1.Rpc-Api模块构建 4 | 5 |  6 | 7 | 8 | 9 | 首先我们分析一下Dubbo的原理,才可以进一步构建RPC。总体流程来说,基于一个公共接口。服务端这一方有具体的实现。启动注册中心,主要有ZK、Nacos、Rureka等。服务端将服务注册到注册中心,而客户端通过服务名从注册中心获取服务,通过注册中心的地址,实现远程调用服务端的服务的具体实现。当然其中还涉及到很多细节,我们主要从最基础的组件进一步构建。 10 | 11 | 原理很简单,但是实现值得商榷,例如**客户端怎么知道服务端的地址**?**客户端怎么告诉服务端我要调用的接口**?**客户端怎么传递参数**?**只有接口客户端怎么生成实现类**……等等等等。 12 | 13 | 好了,下面我们进行模块划分。首先应该有一个RPC-API 将公共的接口放入。 14 | 15 | RPC-API : 公共接口 16 | 17 | RPC-Common : 公共组件 18 | 19 | RPC-Core : 核心组件 20 | 21 | RPC-Client : 客户端 22 | 23 | RPC-Server :服务端 24 | 25 | ### Rpc-Api中组件编写 26 | 27 | `HelloService` 接口调用 28 | 29 | `DataObject` 传输数据封装 30 | 31 | `ByeService` 结束接口调用 32 | 33 | ## 2.Rpc-common模块构建 34 | 35 | `entity.RpcRequest` 对于Rpc调用来说,就是一个请求和响应的过程。因为在传输过程中,需要封装自定义的数据格式信息。因此,自定义,首先需要给一个请求一个随机的ID,这里采用的是UUID生成。服务名 可以将接口名作为服务名,方法作为方法调用、以及对应的方法参数类型、方法参数、因为在功能中,我们还要首先一个心跳机制,所以加一个心跳是否处于心跳。 36 | 37 | `entity.RpcResponse` 响应的数据,我们可以定义一个ID,请求与响应的ID必须一致。以及返回的状态码,可以用枚举写。以及传输中数据。补充信息。 38 | 39 | ================================================== 40 | 41 | `ennumeration.PackageType` 数据的传输格式 无非就是 请求 和 响应 42 | 43 | `enumeration.ResponseCode` 响应状态码 成功200 失败 500 对应信息 44 | 45 | `enumeration.RpcError` 异常错误 46 | 47 | `enumeration.SerializerCode` 序列号编码 序列化方式 48 | 49 | ================================================== 50 | 51 | `exception.RpcException` rpc调用异常 52 | 53 | `SerializeException` 序列化异常 54 | 55 | ================================================== 56 | 57 | `factory.SingleFactory` 单例工厂类 58 | 59 | `factory.ThreadPoolFactory` 线程池工厂 60 | 61 | ================================================= 62 | 63 | `util.NacosUtil` Nacos连接工具 64 | 65 | 主要方法有注册服务,通过ip地址+服务名。根据服务名获取所有的服务。注销服务。每次启动的时候。先注销其之前的服务。程序停止,删除所有服务。 66 | 67 | `util.ReflectUtil` 获取栈调用轨迹。 68 | 69 | `util.RpcMessageChecker` 判断请求和响应是否正常。 70 | 71 | ## 3.Rpc-core模块构建 72 | 73 | ### 注解层 74 | 75 | `annotation.Service` 注解 76 | 77 | `annitation.@SacnService` 扫描注解 78 | 79 | ================================================= 80 | 81 | ### 编解码层 82 | 83 | `codec.commoDecoder` 判断是否是规定的传输规范 84 | 85 | `codec.commoEncoder` 编辑传输规范 86 | 87 | 编码器因为是通过通道所以需要继承MessageToByteEncoder,我们自定义一套传输规范。 88 | 89 | ``` 90 | +---------------+---------------+-----------------+-------------+ 91 | | Magic Number | Package Type | Serializer Type | Data Length | 92 | | 4 bytes | 4 bytes | 4 bytes | 4 bytes | 93 | +---------------+---------------+-----------------+-------------+ 94 | | Data Bytes | 95 | | Length: ${Data Length} | 96 | +---------------------------------------------------------------+ 97 | ``` 98 | 99 | 魔数:使用java版本咖啡。包类型 请求或者响应包 序列化方式类型 数据长度 以及数据。 100 | 101 | ================================================= 102 | 103 | ### 请求拦截层 104 | 105 | `handler.RequestHandler` 根据请求参数,调用对应的服务,而最终通过动态代理实现。 106 | 107 | ================================================= 108 | 109 | ### 回调层 110 | 111 | `hook.ShutDownHook` 当系统停止时,清除服务。线程池关闭。 112 | 113 | ================================================= 114 | 115 | ### 负载均衡层 116 | 117 | `loadbalancer.LoadBalancer ` 负载策略规范 118 | 119 | `loadbalancer.RandomLoadBalancer ` 随机策略 120 | 121 | `loadbalancer.RoundRobinLoadBalancer` 轮询策略 122 | 123 | ================================================= 124 | 125 | ### 服务提供者 126 | 127 | `provider.serviceProvider` 服务添加和查找规范 128 | 129 | `provider.ServiceProviderImpl ` 根据服务名查找服务和添加服务。主要思路是用两个Map存储,一个存储记录的map,一个记录服务。 130 | 131 | ================================================= 132 | 133 | ### 服务注册与发现 134 | 135 | `registry.NacosServiceDiscovery` 通过负载策略查找服务名具体提供实例 136 | 137 | `registry.NacosServiceRegistry` 注册到Nacos中 138 | 139 | `registry.ServiceDiscovery` 服务发现接口 通过服务名查找服务 140 | 141 | `registry.ServiceRegistry` 服务注册接口 通过服务名和地址信息(ip+port)注册到Nacos中 142 | 143 | ================================================= 144 | 145 | ### 序列化 146 | 147 | `serializer.CommonSerializer` 序列化接口 148 | 149 | `serializer.HessianSerializer` Hessian方式 150 | 151 | `serializer.JsonSerialilizer` Json格式 152 | 153 | `serializer.KryoSerialilizer` Kryo格式 154 | 155 | `serializer.ProtobufSerialilizer` Protobu格式 156 | 157 | ================================================= 158 | 159 | ### 核心 160 | 161 | `transport.RpcServer` 服务端接口规范 162 | 163 | `transport.RpcClient` 客户端接口规范 164 | 165 | `AbstractRpcServer` 主要初始化的时候,扫描带有@Service @ScanService的注解。并将包下的类进行创建对应的对象。 166 | 167 | `RpcClientProxy` 动态创建代理类,通过方法invoke 生成对应的RcpRequest对象发送给服务端,通过异步回调。 168 | 169 | `NettyServerHandler` 心跳检测 + 发送数据 170 | 171 | `NettyServer`Netty服务端 172 | 173 | 174 | 175 | ### 服务端主要流程 176 | 177 | 1.从测试端拿到端口号和Ip地址,以及序列化方式(默认就是Kryo方式),初始化的过程中,创建服务提供者和服务注册者。因为NettyServer继承AbstractRpcServer,并调用了`scanServices()` 。 178 | 179 | 2.`scanServices()` 根据从递归调用栈中拿到栈底的栈帧,也就是启动Main的类进行扫描。将带有@ScanService的注解类加载,对应的基础包,包下的@Service注解 反射生成。对应的接口为服务名。实例为服务。调用了服务提供者和服务注册者。因为是对于服务端来说,所以服务端提供了服务提供和服务注册功能。 180 | 181 | 3.`start()` 设置一下,如果程序终止之前,将服务全部删除。Netty创建流程。获取到管道。设置心跳参数,编码器,解码器。这里要说一下,编码器和解码器是相对的。当服务端接收到数据时,会采用解码器进行解析数据,之后,服务端发送数据会进行编码器,将数据进行编码。因为我们在程序中设置了传输格式,所以必须符合才可以,否则的话,会出现问题。除了编码器和解码器,加了一个过滤器,数据的拦截。首先检测是否是心跳,如果是心跳则直接返回。否则的话 是客户端的数据,通过`RequestHandler`过滤器进行处理。**实际上处理数据的就是通过RequestHandler来处理的**,从请求中拿到服务名,通过方法名和方法参数获取对应的方法,调用invoke处理。 182 | 183 | 如果通道正常,将RPCResponse响应给客户端。 如果长时间检测到心跳未回应。然后服务端关闭。 184 | 185 | ### 客户端主要流程 186 | 187 | 1.客户端通过序列化方式和随机负载均衡以及服务发现功能。完成初始化。 188 | 189 | 2.通过客户端生成代理类。生成对应的HelloService.class代理对象。因为对象是代理,所以只要通过方法调用就会触发invoke的请求。**而主要逻辑就是invoke方法** 190 | 191 | 3.**invoke()**,生成一个RpcRequest对象,心跳机制默认是false 如果请求Client属于NettyClient 通过异步回调机制,发送请求。通过响应拿到rpcResponse对象, 192 | 193 | 4.**sendRequest()**,通过服务名 拿到查找对应服务,将数据写入到通道中。 194 | 195 | ## 4.Nacos服务启动 196 | 197 | startup.cmd -m standalone 198 | 199 | http://127.0.0.1:8848/nacos/index.html 200 | 201 | 202 | 203 | 204 | 205 | ## 问题迭代 206 | 207 | 1.怎么实现的同步?你的调用为什么是同步的? 208 | 209 | 答: Netty是同步非阻塞的,我在项目中使用的netty进行网络传输。 210 | 211 | 212 | 213 | 2.客户端发请求的时候,封装请求之后通过tcp发送到客户端的吗? 214 | 215 | 答:是的 216 | 217 | 218 | 219 | 3.客户端和服务端都用的tcp? server那边怎么处理的请求 220 | 221 | 答:都用的tcp, server那边先反序列化获得请求类,请求类RPCRequest里面包含需要调用的方法和参数,执行对应方法后会把结果封装成RPCResponse类返回给客户端 222 | 223 | 224 | 225 | 4.是在netty的线程里面直接调用了业务代码吗? 226 | 227 | 答:不是,netty传输的是序列化后的字节码。需要在服务端桩反序列化后执行业务代码。 228 | -------------------------------------------------------------------------------- /rpc-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | rpc-api 13 | 14 | 15 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/ncst/api/ByeService.java: -------------------------------------------------------------------------------- 1 | package com.ncst.api; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/19/16:12 8 | * @Description: 9 | */ 10 | public interface ByeService { 11 | 12 | String bye (String name); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/ncst/api/DataObject.java: -------------------------------------------------------------------------------- 1 | package com.ncst.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/19/16:11 14 | * @Description: 15 | */ 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class DataObject implements Serializable { 20 | 21 | private Integer id; 22 | 23 | private String message; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/ncst/api/HelloService.java: -------------------------------------------------------------------------------- 1 | package com.ncst.api; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/19/16:11 8 | * @Description: 用户交互接口 9 | */ 10 | public interface HelloService { 11 | String hello(DataObject object); 12 | } 13 | -------------------------------------------------------------------------------- /rpc-common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | rpc-common 13 | 14 | 15 | 16 | com.google.guava 17 | guava 18 | ${guava.version} 19 | 20 | 21 | com.alibaba.nacos 22 | nacos-client 23 | 1.3.0 24 | 25 | 26 | 27 | commons-codec 28 | commons-codec 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/entity/RpcRequest.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.entity; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/19/16:38 14 | * @Description: 15 | */ 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class RpcRequest implements Serializable { 20 | 21 | /*** 22 | * 传递的序号 23 | */ 24 | private String id; 25 | 26 | /** 27 | * 接口名称 对标接口名-一个服务 28 | */ 29 | private String interfaceName; 30 | 31 | /*** 32 | * 方法名称 一个方法 33 | */ 34 | private String methodName; 35 | 36 | /*** 37 | * 方法参数 38 | */ 39 | private Object [] param; 40 | 41 | /** 42 | * 参数类型 43 | */ 44 | private Class> [] methodTypes; 45 | 46 | /*** 47 | * 是否心跳 48 | */ 49 | private boolean heartBeat; 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/entity/RpcResponse.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.entity; 2 | 3 | import com.ncst.rpc.enumeration.ResponseCode; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/19/16:16 14 | * @Description: 15 | */ 16 | @Data 17 | @NoArgsConstructor 18 | public class RpcResponse implements Serializable { 19 | 20 | /** 21 | * 响应对应的请求号 22 | */ 23 | private String requestId; 24 | /** 25 | * 响应状态码 26 | */ 27 | private Integer statusCode; 28 | /** 29 | * 响应状态补充信息 30 | */ 31 | private String message; 32 | /** 33 | * 响应数据 34 | */ 35 | private T data; 36 | 37 | public static RpcResponse success(T data, String requestId) { 38 | RpcResponse response = new RpcResponse<>(); 39 | response.setRequestId(requestId); 40 | response.setStatusCode(ResponseCode.SUCCESS.getCode()); 41 | response.setData(data); 42 | return response; 43 | } 44 | 45 | public static RpcResponse fail(ResponseCode code, String requestId) { 46 | RpcResponse response = new RpcResponse<>(); 47 | response.setRequestId(requestId); 48 | response.setStatusCode(code.getCode()); 49 | response.setMessage(code.getMessage()); 50 | return response; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/enumeration/PackageType.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.enumeration; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/19/16:17 11 | * @Description: 自定义数据协议中 PackageType 表名是一个请求还是响应 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | public enum PackageType { 16 | 17 | REQUEST_PACK(0),//请求 18 | RESPONSE_PACK(1);//响应 19 | 20 | private final int code; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/enumeration/ResponseCode.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.enumeration; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/19/16:17 11 | * @Description: 响应状态码 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | public enum ResponseCode { 16 | 17 | SUCCESS(200, "调用方法成功"),//成功 18 | FAIL(500, "调用方法失败"), //失败 19 | METHOD_NOT_FOUND(500, "未找到指定方法"), //没有找到对应的方法 20 | CLASS_NOT_FOUND(500, "未找到指定类");//没有找到对应的类 21 | 22 | private final int code; 23 | private final String message; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/enumeration/RpcError.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.enumeration; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/19/16:18 11 | * @Description: Rpc错误 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | public enum RpcError { 16 | 17 | //unknown_error 18 | UNKNOWN_ERROR("出现未知错误"), 19 | //service_sacn_packeg_not_fonud 20 | SERVICE_SCAN_PACKAGE_NOT_FOUND("启动类ServiceScan注解缺失"), 21 | //client_connect_seerver_failure 22 | CLIENT_CONNECT_SERVER_FAILURE("客户端连接服务端失败"), 23 | //service_invocation_failure 24 | SERVICE_INVOCATION_FAILURE("服务调用出现失败"), 25 | //service_not_found 26 | SERVICE_NOT_FOUND("找不到对应的服务"), 27 | //service_not_implement_any_interface 28 | SERVICE_NOT_IMPLEMENT_ANY_INTERFACE("注册的服务未实现接口"), 29 | //unknown_protocol 30 | UNKNOWN_PROTOCOL("不识别的协议包"), 31 | //unknown_serializer 32 | UNKNOWN_SERIALIZER("不识别的(反)序列化器"), 33 | //unknown_package_type 34 | UNKNOWN_PACKAGE_TYPE("不识别的数据包类型"), 35 | //serializer_not_found 36 | SERIALIZER_NOT_FOUND("找不到序列化器"), 37 | //response_not_match 38 | RESPONSE_NOT_MATCH("响应与请求号不匹配"), 39 | //failed_to_connect_to_service_registry 40 | FAILED_TO_CONNECT_TO_SERVICE_REGISTRY("连接注册中心失败"), 41 | //regsiter_service_failed 42 | REGISTER_SERVICE_FAILED("注册服务失败"); 43 | 44 | private final String message; 45 | 46 | } -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/enumeration/SerializerCode.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.enumeration; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/19/16:18 11 | * @Description: 序列化编号 12 | */ 13 | @AllArgsConstructor 14 | @Getter 15 | public enum SerializerCode { 16 | 17 | KRYO(0),//kryo 18 | JSON(1),//json 19 | HESSIAN(2),//hessian 20 | PROTOBUF(3);//protobuf 21 | 22 | private final int code; 23 | 24 | } -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/exception/RpcException.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.exception; 2 | 3 | import com.ncst.rpc.enumeration.RpcError; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/19/16:59 10 | * @Description: RPC调用异常 11 | */ 12 | public class RpcException extends RuntimeException { 13 | 14 | public RpcException (RpcError rpcError, String detail) { 15 | super(rpcError.getMessage() +" : "+ detail); 16 | } 17 | 18 | public RpcException(String message,Throwable cause) { 19 | super(message,cause); 20 | } 21 | 22 | public RpcException(RpcError rpcError) { 23 | super(rpcError.getMessage()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/exception/SerializeException.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.exception; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/19/17:07 8 | * @Description: 序列化异常 9 | */ 10 | public class SerializeException extends RuntimeException{ 11 | 12 | public SerializeException (String msg) { 13 | super(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/factory/SingletonFactory.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.factory; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/19/17:11 13 | * @Description: 工厂类 14 | */ 15 | public class SingletonFactory { 16 | 17 | private static Map objectMap = new ConcurrentHashMap<>(); 18 | 19 | private SingletonFactory () {} 20 | 21 | /*** 22 | * 根据Class获取某一个对象 23 | * @param clazz 24 | * @param 25 | * @return 26 | */ 27 | public static T getInstance (Class clazz) { 28 | Object instance = objectMap.get(clazz); 29 | synchronized (clazz) { 30 | if (instance == null) { 31 | try { 32 | instance = clazz.newInstance(); 33 | objectMap.put(clazz,instance); 34 | } catch (InstantiationException | IllegalAccessException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | } 39 | return clazz.cast(instance); 40 | } 41 | 42 | 43 | public static void main(String[] args) { 44 | RpcRequest instance = getInstance(RpcRequest.class); 45 | System.out.println(instance); 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/factory/ThreadPoolFactory.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.factory; 2 | 3 | import com.google.common.util.concurrent.ThreadFactoryBuilder; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.Map; 8 | import java.util.concurrent.*; 9 | 10 | /** 11 | * 创建 ThreadPool(线程池) 的工具类. 来自JavaGuide 12 | * 13 | * @author shuang.kou 14 | * @createTime 2020年05月26日 16:00:00 15 | */ 16 | public class ThreadPoolFactory { 17 | /** 18 | * 线程池参数 19 | */ 20 | private static final int CORE_POOL_SIZE = 10;//核心线程 21 | private static final int MAXIMUM_POOL_SIZE_SIZE = 100;//最大 22 | private static final int KEEP_ALIVE_TIME = 1;//保持连接 23 | private static final int BLOCKING_QUEUE_CAPACITY = 100;//阻塞队列大小 24 | 25 | private final static Logger logger = LoggerFactory.getLogger(ThreadPoolFactory.class); 26 | 27 | private static Map threadPollsMap = new ConcurrentHashMap<>(); 28 | 29 | private ThreadPoolFactory() { 30 | } 31 | 32 | public static ExecutorService createDefaultThreadPool(String threadNamePrefix) { 33 | return createDefaultThreadPool(threadNamePrefix, false); 34 | } 35 | 36 | public static ExecutorService createDefaultThreadPool(String threadNamePrefix, Boolean daemon) { 37 | ExecutorService pool = threadPollsMap.computeIfAbsent(threadNamePrefix, k -> createThreadPool(threadNamePrefix, daemon)); 38 | if (pool.isShutdown() || pool.isTerminated()) { 39 | threadPollsMap.remove(threadNamePrefix); 40 | pool = createThreadPool(threadNamePrefix, daemon); 41 | threadPollsMap.put(threadNamePrefix, pool); 42 | } 43 | return pool; 44 | } 45 | 46 | public static void shutDownAll() { 47 | logger.info("关闭所有线程池..."); 48 | threadPollsMap.entrySet().parallelStream().forEach(entry -> { 49 | ExecutorService executorService = entry.getValue(); 50 | executorService.shutdown(); 51 | logger.info("关闭线程池 [{}] [{}]", entry.getKey(), executorService.isTerminated()); 52 | try { 53 | executorService.awaitTermination(10, TimeUnit.SECONDS); 54 | } catch (InterruptedException ie) { 55 | logger.error("关闭线程池失败!"); 56 | executorService.shutdownNow(); 57 | } 58 | }); 59 | } 60 | 61 | private static ExecutorService createThreadPool(String threadNamePrefix, Boolean daemon) { 62 | BlockingQueue workQueue = new ArrayBlockingQueue<>(BLOCKING_QUEUE_CAPACITY); 63 | ThreadFactory threadFactory = createThreadFactory(threadNamePrefix, daemon); 64 | return new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE_SIZE, KEEP_ALIVE_TIME, TimeUnit.MINUTES, workQueue, threadFactory); 65 | } 66 | 67 | 68 | /** 69 | * 创建 ThreadFactory 。如果threadNamePrefix不为空则使用自建ThreadFactory,否则使用defaultThreadFactory 70 | * 71 | * @param threadNamePrefix 作为创建的线程名字的前缀 72 | * @param daemon 指定是否为 Daemon Thread(守护线程) 73 | * @return ThreadFactory 74 | */ 75 | private static ThreadFactory createThreadFactory(String threadNamePrefix, Boolean daemon) { 76 | if (threadNamePrefix != null) { 77 | if (daemon != null) { 78 | return new ThreadFactoryBuilder().setNameFormat(threadNamePrefix + "-%d").setDaemon(daemon).build(); 79 | } else { 80 | return new ThreadFactoryBuilder().setNameFormat(threadNamePrefix + "-%d").build(); 81 | } 82 | } 83 | return Executors.defaultThreadFactory(); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/util/NacosUtil.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.util; 2 | 3 | import com.alibaba.nacos.api.exception.NacosException; 4 | import com.alibaba.nacos.api.naming.NamingFactory; 5 | import com.alibaba.nacos.api.naming.NamingService; 6 | import com.alibaba.nacos.api.naming.pojo.Instance; 7 | import com.ncst.rpc.enumeration.RpcError; 8 | import com.ncst.rpc.exception.RpcException; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.net.InetSocketAddress; 13 | import java.util.HashSet; 14 | import java.util.Iterator; 15 | import java.util.List; 16 | import java.util.Set; 17 | 18 | /** 19 | * 管理Nacos连接等工具类 20 | * @author i 21 | */ 22 | public class NacosUtil { 23 | 24 | private static final Logger logger = LoggerFactory.getLogger(NacosUtil.class); 25 | 26 | private static final NamingService namingService;//名称服务 27 | private static final Set serviceNames = new HashSet<>(); //服务名称 28 | private static InetSocketAddress address;//ip地址 29 | 30 | private static final String SERVER_ADDR = "127.0.0.1:8848";//localhost+port 31 | 32 | static { 33 | namingService = getNacosNamingService(); 34 | } 35 | 36 | /**** 37 | * 获取Nacos服务 38 | * @return 39 | */ 40 | public static NamingService getNacosNamingService() { 41 | try { 42 | //创建名称服务 43 | return NamingFactory.createNamingService(SERVER_ADDR); 44 | } catch (NacosException e) { 45 | logger.error("连接到Nacos时有错误发生: ", e); 46 | throw new RpcException(RpcError.FAILED_TO_CONNECT_TO_SERVICE_REGISTRY); 47 | } 48 | } 49 | 50 | /**** 51 | * 注册服务 52 | * @param serviceName 53 | * @param address 54 | * @throws NacosException 55 | */ 56 | public static void registerService(String serviceName, InetSocketAddress address) throws NacosException { 57 | namingService.registerInstance(serviceName, address.getHostName(), address.getPort()); 58 | NacosUtil.address = address; 59 | serviceNames.add(serviceName); 60 | } 61 | 62 | /**** 63 | * 获取所有服务实例 64 | * @param serviceName 65 | * @return 66 | * @throws NacosException 67 | */ 68 | public static List getAllInstance(String serviceName) throws NacosException { 69 | return namingService.getAllInstances(serviceName); 70 | } 71 | 72 | /***** 73 | * 注销服务 74 | */ 75 | public static void clearRegistry() { 76 | if(!serviceNames.isEmpty() && address != null) { 77 | String host = address.getHostName(); 78 | int port = address.getPort(); 79 | Iterator iterator = serviceNames.iterator(); 80 | while(iterator.hasNext()) { 81 | String serviceName = iterator.next(); 82 | try { 83 | namingService.deregisterInstance(serviceName, host, port); 84 | } catch (NacosException e) { 85 | logger.error("注销服务 {} 失败", serviceName, e); 86 | } 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/util/ReflectUtil.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.util; 2 | 3 | import java.io.File; 4 | import java.io.FileFilter; 5 | import java.io.IOException; 6 | import java.net.JarURLConnection; 7 | import java.net.URL; 8 | import java.net.URLDecoder; 9 | import java.util.Enumeration; 10 | import java.util.LinkedHashSet; 11 | import java.util.Set; 12 | import java.util.jar.JarEntry; 13 | import java.util.jar.JarFile; 14 | 15 | /** 16 | * @author i 17 | */ 18 | public class ReflectUtil { 19 | 20 | /***** 21 | * 获取main方法所在的类 22 | * @return 23 | */ 24 | public static String getStackTrace() { 25 | //提供的堆栈跟踪信息的印刷 printStackTrace()编程访问。 26 | //返回一个堆栈跟踪元素的数组,每个数组代表一个堆栈帧 27 | //数组的最后一个元素(假设数组的长度为非0)表示堆栈的底部,这是序列中的第一个方法调用。 28 | //main方法调用栈 方法的调用本质来说就是栈帧的入栈和出栈的操作,而main方法一定是在栈底的 29 | //获取main所在的类 30 | StackTraceElement[] stack = new Throwable().getStackTrace(); 31 | return stack[stack.length - 1].getClassName(); 32 | } 33 | 34 | public static Set> getClasses(String packageName) { 35 | Set> classes = new LinkedHashSet<>(); 36 | boolean recursive = true; 37 | String packageDirName = packageName.replace('.', '/'); 38 | Enumeration dirs; 39 | try { 40 | dirs = Thread.currentThread().getContextClassLoader().getResources( 41 | packageDirName); 42 | // 循环迭代下去 43 | while (dirs.hasMoreElements()) { 44 | // 获取下一个元素 45 | URL url = dirs.nextElement(); 46 | // 得到协议的名称 47 | String protocol = url.getProtocol(); 48 | // 如果是以文件的形式保存在服务器上 49 | if ("file".equals(protocol)) { 50 | // 获取包的物理路径 51 | String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); 52 | // 以文件的方式扫描整个包下的文件 并添加到集合中 53 | findAndAddClassesInPackageByFile(packageName, filePath, 54 | recursive, classes); 55 | } else if ("jar".equals(protocol)) { 56 | // 如果是jar包文件 57 | // 定义一个JarFile 58 | JarFile jar; 59 | try { 60 | // 获取jar 61 | jar = ((JarURLConnection) url.openConnection()) 62 | .getJarFile(); 63 | // 从此jar包 得到一个枚举类 64 | Enumeration entries = jar.entries(); 65 | // 同样的进行循环迭代 66 | while (entries.hasMoreElements()) { 67 | // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 68 | JarEntry entry = entries.nextElement(); 69 | String name = entry.getName(); 70 | // 如果是以/开头的 71 | if (name.charAt(0) == '/') { 72 | // 获取后面的字符串 73 | name = name.substring(1); 74 | } 75 | // 如果前半部分和定义的包名相同 76 | if (name.startsWith(packageDirName)) { 77 | int idx = name.lastIndexOf('/'); 78 | // 如果以"/"结尾 是一个包 79 | if (idx != -1) { 80 | // 获取包名 把"/"替换成"." 81 | packageName = name.substring(0, idx) 82 | .replace('/', '.'); 83 | } 84 | // 如果可以迭代下去 并且是一个包 85 | if ((idx != -1) || recursive) { 86 | // 如果是一个.class文件 而且不是目录 87 | if (name.endsWith(".class") 88 | && !entry.isDirectory()) { 89 | // 去掉后面的".class" 获取真正的类名 90 | String className = name.substring( 91 | packageName.length() + 1, name 92 | .length() - 6); 93 | try { 94 | // 添加到classes 95 | classes.add(Class 96 | .forName(packageName + '.' 97 | + className)); 98 | } catch (ClassNotFoundException e) { 99 | // log 100 | // .error("添加用户自定义视图类错误 找不到此类的.class文件"); 101 | e.printStackTrace(); 102 | } 103 | } 104 | } 105 | } 106 | } 107 | } catch (IOException e) { 108 | // log.error("在扫描用户定义视图时从jar包获取文件出错"); 109 | e.printStackTrace(); 110 | } 111 | } 112 | } 113 | } catch (IOException e) { 114 | e.printStackTrace(); 115 | } 116 | 117 | return classes; 118 | } 119 | 120 | private static void findAndAddClassesInPackageByFile(String packageName, 121 | String packagePath, final boolean recursive, Set> classes) { 122 | // 获取此包的目录 建立一个File 123 | File dir = new File(packagePath); 124 | // 如果不存在或者 也不是目录就直接返回 125 | if (!dir.exists() || !dir.isDirectory()) { 126 | // log.warn("用户定义包名 " + packageName + " 下没有任何文件"); 127 | return; 128 | } 129 | // 如果存在 就获取包下的所有文件 包括目录 130 | File[] dirfiles = dir.listFiles(new FileFilter() { 131 | // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) 132 | public boolean accept(File file) { 133 | return (recursive && file.isDirectory()) 134 | || (file.getName().endsWith(".class")); 135 | } 136 | }); 137 | // 循环所有文件 138 | for (File file : dirfiles) { 139 | // 如果是目录 则继续扫描 140 | if (file.isDirectory()) { 141 | findAndAddClassesInPackageByFile(packageName + "." 142 | + file.getName(), file.getAbsolutePath(), recursive, 143 | classes); 144 | } else { 145 | // 如果是java类文件 去掉后面的.class 只留下类名 146 | String className = file.getName().substring(0, 147 | file.getName().length() - 6); 148 | try { 149 | // 添加到集合中去 150 | //classes.add(Class.forName(packageName + '.' + className)); 151 | //经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净 152 | classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); 153 | } catch (ClassNotFoundException e) { 154 | // log.error("添加用户自定义视图类错误 找不到此类的.class文件"); 155 | e.printStackTrace(); 156 | } 157 | } 158 | } 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /rpc-common/src/main/java/com/ncst/rpc/util/RpcMessageChecker.java: -------------------------------------------------------------------------------- 1 | package com.ncst.rpc.util; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.enumeration.ResponseCode; 6 | import com.ncst.rpc.enumeration.RpcError; 7 | import com.ncst.rpc.exception.RpcException; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | 12 | /** 13 | * 检查响应与请求 14 | * 15 | * @author i 16 | */ 17 | public class RpcMessageChecker { 18 | 19 | public static final String INTERFACE_NAME = "interfaceName"; 20 | private static final Logger logger = LoggerFactory.getLogger(RpcMessageChecker.class); 21 | 22 | private RpcMessageChecker() { 23 | } 24 | 25 | public static void check(RpcRequest rpcRequest, RpcResponse rpcResponse) { 26 | if (rpcResponse == null) { 27 | logger.error("...调用服务失败,serviceName:{}...", rpcRequest.getInterfaceName()); 28 | throw new RpcException(RpcError.SERVICE_INVOCATION_FAILURE, INTERFACE_NAME + ":" + rpcRequest.getInterfaceName()); 29 | } 30 | //请求ID和响应ID不是同一个 31 | if (!rpcRequest.getId().equals(rpcResponse.getRequestId())) { 32 | throw new RpcException(RpcError.RESPONSE_NOT_MATCH, INTERFACE_NAME + ":" + rpcRequest.getInterfaceName()); 33 | } 34 | //状态码非200 35 | if (rpcResponse.getStatusCode() == null || !rpcResponse.getStatusCode().equals(ResponseCode.SUCCESS.getCode())) { 36 | logger.error("调用服务失败,serviceName:{},RpcResponse:{}", rpcRequest.getInterfaceName(), rpcResponse); 37 | throw new RpcException(RpcError.SERVICE_INVOCATION_FAILURE, INTERFACE_NAME + ":" + rpcRequest.getInterfaceName()); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /rpc-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | rpc-core 13 | 14 | 20 | 21 | com.ncst 22 | rpc-common 23 | 1.0-SNAPSHOT 24 | compile 25 | 26 | 27 | io.netty 28 | netty-all 29 | ${netty-version} 30 | 31 | 32 | com.fasterxml.jackson.core 33 | jackson-core 34 | 2.11.0 35 | 36 | 37 | com.fasterxml.jackson.core 38 | jackson-databind 39 | 2.11.0 40 | 41 | 42 | com.fasterxml.jackson.core 43 | jackson-annotations 44 | 2.11.0 45 | 46 | 47 | com.esotericsoftware 48 | kryo 49 | 4.0.2 50 | 51 | 52 | com.caucho 53 | hessian 54 | 4.0.63 55 | 56 | 57 | io.protostuff 58 | protostuff-core 59 | 1.7.2 60 | 61 | 62 | io.protostuff 63 | protostuff-runtime 64 | 1.7.2 65 | 66 | 67 | com.alibaba.nacos 68 | nacos-client 69 | 1.3.0 70 | 71 | 72 | com.sun.xml.ws 73 | jaxws-rt 74 | 2.1.4 75 | 76 | 77 | 78 | javax.activation 79 | activation 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.apache.maven.plugins 90 | maven-compiler-plugin 91 | 3.5.1 92 | 93 | 1.8 94 | 1.8 95 | UTF-8 96 | 100 | 101 | 102 | 103 | 105 | ${java.home}\lib\rt.jar;${java.home}\lib\jce.jar 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/annotation/Service.java: -------------------------------------------------------------------------------- 1 | package com.ncst.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/19/18:01 13 | * @Description: 表示一个服务提供类,用于远程接口的实现类 14 | */ 15 | @Target(ElementType.TYPE) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface Service { 18 | 19 | public String name() default ""; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/annotation/ServiceScan.java: -------------------------------------------------------------------------------- 1 | package com.ncst.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/19/17:57 13 | * @Description: 服务基础扫描包 14 | */ 15 | @Target(ElementType.TYPE)//元素类型 16 | @Retention(RetentionPolicy.RUNTIME)//运行时 17 | public @interface ServiceScan { 18 | 19 | public String value () default ""; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/codec/CommoDecoder.java: -------------------------------------------------------------------------------- 1 | package com.ncst.codec; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.enumeration.PackageType; 6 | import com.ncst.rpc.enumeration.RpcError; 7 | import com.ncst.rpc.exception.RpcException; 8 | import com.ncst.serializer.CommonSerializer; 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import io.netty.handler.codec.ReplayingDecoder; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * 日拱一卒,不期速成 19 | * 20 | * @Auther: i 21 | * @Date: 2020/10/20/21:00 22 | * @Description: 解码器 23 | * ReplayingDecoder 继承了ByteToMessageDecoder 24 | * 判断参数 25 | */ 26 | public class CommoDecoder extends ReplayingDecoder { 27 | 28 | private static final Logger logger = LoggerFactory.getLogger(CommoDecoder.class); 29 | 30 | private int MAGIC_NUMBERS = 0xCAFEBABE; 31 | 32 | /***** 33 | * 编码处理 34 | * @param channelHandlerContext 35 | * @param byteBuf 36 | * @param list 37 | * @throws Exception 38 | */ 39 | @Override 40 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) throws Exception { 41 | //魔数版本 42 | int magicNumber = byteBuf.readInt(); 43 | if (magicNumber != MAGIC_NUMBERS) { 44 | logger.error("...错误的魔数号码..."); 45 | throw new RpcException(RpcError.UNKNOWN_PROTOCOL); 46 | } 47 | 48 | int packageType = byteBuf.readInt(); 49 | Class> packageClass = null; 50 | //包类型 51 | if (packageType == PackageType.REQUEST_PACK.getCode()) { 52 | packageClass = RpcRequest.class; 53 | } else if (packageType == PackageType.RESPONSE_PACK.getCode()) { 54 | packageClass = RpcResponse.class; 55 | } else { 56 | logger.error("...响应与请求不符合..."); 57 | throw new RpcException(RpcError.UNKNOWN_PACKAGE_TYPE); 58 | } 59 | //序列化类型 60 | int serializer = byteBuf.readInt(); 61 | CommonSerializer commonSerializer = CommonSerializer.getBytes(serializer); 62 | if (commonSerializer == null) { 63 | logger.error("...序列化出现问题..."); 64 | throw new RpcException(RpcError.SERIALIZER_NOT_FOUND); 65 | } 66 | //数据 67 | int length = byteBuf.readInt(); 68 | byte [] bytes = new byte[length]; 69 | byteBuf.readBytes(bytes); 70 | Object obj = commonSerializer.deserialize(bytes, packageClass); 71 | list.add(obj); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/codec/CommonEncoder.java: -------------------------------------------------------------------------------- 1 | package com.ncst.codec; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.enumeration.PackageType; 5 | import com.ncst.serializer.CommonSerializer; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.handler.codec.MessageToByteEncoder; 9 | 10 | /** 11 | * 日拱一卒,不期速成 12 | * 13 | * @Auther: i 14 | * @Date: 2020/10/20/20:40 15 | * @Description: 编码器 自定义规则 16 | * Magic Number Package Type Serializer Type Data length 17 | * 4 bytes 4 bytes 4 bytes 4 bytes 18 | * 19 | * 魔数+包类型+序列化类型+data 20 | * 继承MessageToByteEncoder转换成Byte数组,将请求或响应包装成响应包。 21 | */ 22 | public class CommonEncoder extends MessageToByteEncoder { 23 | 24 | //魔数 25 | private static final int MAGIC_NUMBER = 0xCAFEBABE; 26 | 27 | private CommonSerializer commonSerializer; 28 | 29 | public CommonEncoder(CommonSerializer commonSerializer) { 30 | this.commonSerializer = commonSerializer; 31 | } 32 | 33 | /****** 34 | * 因为编码器对于客户端和服务端都会调用,因此需要进行区分,也就是通过数据包的类型来判断request response 35 | * @param ctx 36 | * @param msg 37 | * @param byteBuf 38 | * @throws Exception 39 | */ 40 | @Override 41 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf byteBuf) throws Exception { 42 | byteBuf.writeInt(MAGIC_NUMBER);//魔数 43 | //request 44 | if (msg instanceof RpcRequest) { 45 | byteBuf.writeInt(PackageType.REQUEST_PACK.getCode()); 46 | //response 47 | } else { 48 | byteBuf.writeInt(PackageType.RESPONSE_PACK.getCode()); 49 | } 50 | //序列化方式 51 | byteBuf.writeInt(commonSerializer.getCode()); 52 | byte[] bytes = commonSerializer.serialize(msg);//序列化 53 | byteBuf.writeInt(bytes.length);//length 54 | byteBuf.writeBytes(bytes);//data 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/handler/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.handler; 2 | 3 | import com.ncst.provider.ServiceProvider; 4 | import com.ncst.provider.ServiceProviderImpl; 5 | import com.ncst.rpc.entity.RpcRequest; 6 | import com.ncst.rpc.entity.RpcResponse; 7 | import com.ncst.rpc.enumeration.ResponseCode; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | * 日拱一卒,不期速成 15 | * 16 | * @Auther: i 17 | * @Date: 2020/10/20/18:05 18 | * @Description: 进程过程调用的处理器 19 | */ 20 | public class RequestHandler { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class); 23 | 24 | private static ServiceProvider serviceProcider = null; 25 | 26 | static { 27 | serviceProcider = new ServiceProviderImpl(); 28 | } 29 | 30 | //拦截器 获取rpcRequest请求 31 | public Object handle(RpcRequest rpcRequest) { 32 | //以接口为一个服务 33 | Object service = serviceProcider.getServiceProvider(rpcRequest.getInterfaceName()); 34 | return invokeTargetMethod(rpcRequest, service); 35 | } 36 | 37 | private Object invokeTargetMethod(RpcRequest rpcRequest, Object service) { 38 | Object result = null; 39 | try { 40 | //返回一个 方法对象反映的类或接口的 类对象表示的指定公共成员方法。 41 | //类名 42 | //方法类型 todo 43 | Method method = service.getClass().getMethod(rpcRequest.getMethodName(), rpcRequest.getMethodTypes()); 44 | //todo ? 是调用 45 | result = method.invoke(service, rpcRequest.getParam()); 46 | System.out.println("【 服务 】"+rpcRequest.getInterfaceName()+"【 调用方法 】"+ rpcRequest.getMethodName()); 47 | } catch (Exception e) { 48 | return RpcResponse.fail(ResponseCode.METHOD_NOT_FOUND, rpcRequest.getId()); 49 | } 50 | return result; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/hook/ShutDownHook.java: -------------------------------------------------------------------------------- 1 | package com.ncst.hook; 2 | 3 | import com.ncst.rpc.factory.ThreadPoolFactory; 4 | import com.ncst.rpc.util.NacosUtil; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/20/18:00 13 | * @Description: 14 | */ 15 | public class ShutDownHook { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(ShutDownHook.class); 18 | 19 | private static final ShutDownHook shutDownHook = new ShutDownHook(); 20 | 21 | private ShutDownHook () { 22 | 23 | } 24 | 25 | public static ShutDownHook getInstance () { 26 | return shutDownHook; 27 | } 28 | 29 | /**** 30 | * 当系统关闭之前 调用 将所有注册的服务进行删除。否则下一次启动 客户端 31 | * 会调用只有名字而没有服务的实例,出现错误 32 | */ 33 | public void clearAllService () { 34 | logger.info("...关闭所有服务..."); 35 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 36 | NacosUtil.clearRegistry(); 37 | ThreadPoolFactory.shutDownAll(); 38 | })); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/LoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 日拱一卒,不期速成 9 | * 10 | * @Auther: i 11 | * @Date: 2020/10/20/17:23 12 | * @Description: 负载策略 13 | */ 14 | public interface LoadBalancer { 15 | 16 | /**** 17 | * 获取实例 18 | * @param list 19 | * @return 20 | */ 21 | Instance selectForInstance (List list); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/RandomLoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/20/17:25 13 | * @Description: 随机策略 14 | */ 15 | public class RandomLoadBalancer implements LoadBalancer { 16 | 17 | @Override 18 | public Instance selectForInstance(List list) { 19 | return list.get(new Random().nextInt(list.size())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/RoundRobinLoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 日拱一卒,不期速成 9 | * 10 | * @Auther: i 11 | * @Date: 2020/10/20/17:27 12 | * @Description: 轮询策略 13 | */ 14 | public class RoundRobinLoadBalancer implements LoadBalancer{ 15 | 16 | private int index = 0; 17 | 18 | @Override 19 | public Instance selectForInstance(List list) { 20 | System.out.println(list); 21 | if (index >= list.size()) { 22 | index %= list.size() ; 23 | } 24 | return list.get(index++); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/provider/ServiceProvider.java: -------------------------------------------------------------------------------- 1 | package com.ncst.provider; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/20/16:52 8 | * @Description: 添加服务实例者 9 | */ 10 | public interface ServiceProvider { 11 | 12 | /**** 13 | * 添加服务实例 14 | * @param service 15 | * @param serviceName 16 | * @param 17 | */ 18 | void addServiceProvider(T service, String serviceName); 19 | 20 | 21 | /*** 22 | * 根据服务实例获取服务 23 | * @param serviceName 24 | * @return 25 | */ 26 | Object getServiceProvider(String serviceName); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/provider/ServiceProviderImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.provider; 2 | 3 | import com.ncst.rpc.enumeration.RpcError; 4 | import com.ncst.rpc.exception.RpcException; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/20/17:00 17 | * @Description: 将用户注册的服务存储到Map中 用Map的key记录那些服务已经被注册了 18 | */ 19 | public class ServiceProviderImpl implements ServiceProvider { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(ServiceProviderImpl.class); 22 | 23 | //key存储服务名 value存储服务实例 24 | private static final Map serviceMap = new ConcurrentHashMap<>(); 25 | //存储服务名 26 | private static final Set registeredService = ConcurrentHashMap.newKeySet(); 27 | 28 | @Override 29 | public void addServiceProvider(T service, String serviceName) { 30 | if (service == null || serviceName == null) return; 31 | //存在 32 | if (registeredService.contains(serviceName)) return; 33 | try { 34 | registeredService.add(serviceName); 35 | serviceMap.put(serviceName,service); 36 | logger.info("接口: {} 注册服务: {}",service,serviceName); 37 | } catch (Exception e) { 38 | logger.error("...服务注册过程中失败..."); 39 | } 40 | } 41 | 42 | @Override 43 | public Object getServiceProvider(String serviceName) { 44 | Object o = serviceMap.get(serviceName); 45 | if (o == null) { 46 | throw new RpcException(RpcError.SERVICE_NOT_FOUND); 47 | } 48 | return o; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/NacosServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import com.alibaba.nacos.api.exception.NacosException; 4 | import com.alibaba.nacos.api.naming.pojo.Instance; 5 | import com.ncst.loadbalancer.LoadBalancer; 6 | import com.ncst.loadbalancer.RandomLoadBalancer; 7 | import com.ncst.rpc.enumeration.RpcError; 8 | import com.ncst.rpc.exception.RpcException; 9 | import com.ncst.rpc.util.NacosUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.net.InetSocketAddress; 14 | import java.util.List; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/20/17:33 21 | * @Description: Nacos服务发现 用于客户端调用 22 | */ 23 | public class NacosServiceDiscovery implements ServiceDiscovery{ 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); 26 | 27 | private static LoadBalancer loadBalancer; 28 | 29 | //默认随机负载 30 | public NacosServiceDiscovery (LoadBalancer loadBalancer) { 31 | if (loadBalancer == null) { 32 | loadBalancer = new RandomLoadBalancer(); 33 | } else { 34 | this.loadBalancer = loadBalancer; 35 | } 36 | } 37 | 38 | /***** 39 | * 根据服务名获取服务器-根据不同的策略跳转 40 | * @param serviceName 41 | * @return 42 | */ 43 | @Override 44 | public InetSocketAddress lookUpService(String serviceName) { 45 | try { 46 | List instanceList = NacosUtil.getAllInstance(serviceName); 47 | if (instanceList.size() == 0) { 48 | logger.error("...找不到服务实例..."+serviceName); 49 | throw new RpcException(RpcError.SERVICE_NOT_FOUND); 50 | } 51 | Instance instance = loadBalancer.selectForInstance(instanceList); 52 | return new InetSocketAddress(instance.getIp(),instance.getPort()); 53 | } catch (NacosException e) { 54 | logger.info("...获取服务失败..."); 55 | } 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/NacosServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import com.alibaba.nacos.api.exception.NacosException; 4 | import com.ncst.rpc.enumeration.RpcError; 5 | import com.ncst.rpc.exception.RpcException; 6 | import com.ncst.rpc.util.NacosUtil; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.net.InetSocketAddress; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/20/17:16 17 | * @Description: Nacos服务注册 18 | */ 19 | public class NacosServiceRegistry implements ServiceRegistry{ 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); 22 | 23 | @Override 24 | public void registry(String serviceName, InetSocketAddress inetSocketAddress) { 25 | try { 26 | //util工具类 27 | NacosUtil.registerService(serviceName,inetSocketAddress); 28 | } catch (NacosException e) { 29 | logger.error("...注册服务时发生错误..."); 30 | throw new RpcException(RpcError.REGISTER_SERVICE_FAILED); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/ServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/20/17:19 10 | * @Description: 服务发现接口 11 | */ 12 | public interface ServiceDiscovery { 13 | 14 | 15 | /**** 16 | * 通过服务名查找 17 | * @param serviceName 18 | * @return 19 | */ 20 | InetSocketAddress lookUpService (String serviceName); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/20/17:12 10 | * @Description: 服务注册 11 | */ 12 | public interface ServiceRegistry { 13 | 14 | /**** 15 | * 服务注册 16 | * @param serviceName 服务名称 17 | * @param inetSocketAddress ip地址 18 | */ 19 | void registry (String serviceName, InetSocketAddress inetSocketAddress); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/CommonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/19/18:13 8 | * @Description: 通用的序列化反序列化接口 9 | */ 10 | public interface CommonSerializer { 11 | 12 | Integer KRYO_SERIALIZER = 0; 13 | Integer JSON_SERIALIZER = 1; 14 | Integer HESSION_SERIALIZER = 2; 15 | Integer PROTOBUF_SERIALIZER = 3; 16 | 17 | Integer DEFAULT_SERIALIZER = KRYO_SERIALIZER; 18 | 19 | static CommonSerializer getBytes (int code) { 20 | switch (code) { 21 | case 0 : 22 | return new KryoSerializer(); 23 | case 1: 24 | return new JsonSerializer(); 25 | case 2: 26 | return new HessianSerializer(); 27 | case 3: 28 | return new ProtobufSerializer(); 29 | default: 30 | return null; 31 | } 32 | } 33 | 34 | /*** 35 | * 序列化 将obj 36 | * @param obj 37 | * @return 38 | */ 39 | byte [] serialize (Object obj); 40 | 41 | /**** 42 | * 反序列化 43 | * @param bytes 44 | * @param clazz 45 | * @return 46 | */ 47 | Object deserialize (byte [] bytes,Class> clazz); 48 | 49 | /**** 50 | * 序列化器编号 51 | * @return 52 | */ 53 | int getCode(); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/HessianSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.caucho.hessian.io.HessianInput; 4 | import com.caucho.hessian.io.HessianOutput; 5 | import com.ncst.rpc.enumeration.SerializerCode; 6 | import com.ncst.rpc.exception.SerializeException; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.ByteArrayInputStream; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | 14 | /** 15 | * 日拱一卒,不期速成 16 | * 17 | * @Auther: i 18 | * @Date: 2020/10/20/13:02 19 | * @Description: 基于Hession协议的序列化器 20 | */ 21 | public class HessianSerializer implements CommonSerializer{ 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(HessianSerializer.class); 24 | 25 | @Override 26 | public byte[] serialize(Object obj) { 27 | HessianOutput hessianOutput = null; 28 | //输出 29 | try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){ 30 | hessianOutput = new HessianOutput(baos); 31 | hessianOutput.writeObject(obj); 32 | return baos.toByteArray(); 33 | } catch (Exception e) { 34 | logger.error("...hession序列化发生错误..."); 35 | throw new SerializeException("...hession序列化发生错误..."); 36 | } finally { 37 | if (hessianOutput != null) { 38 | try { 39 | hessianOutput.close(); 40 | } catch (IOException e) { 41 | logger.error("...hession关闭流发生错误..."); 42 | } 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | public Object deserialize(byte[] bytes, Class> clazz) { 49 | HessianInput hessianOutput = null; 50 | try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { 51 | hessianOutput = new HessianInput(bais); 52 | return hessianOutput.readObject(clazz); 53 | } catch (Exception e) { 54 | logger.error("...hession反序列化发生错误..."); 55 | } finally { 56 | if (hessianOutput != null) { 57 | try { 58 | hessianOutput.close(); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | return null; 65 | } 66 | 67 | @Override 68 | public int getCode() { 69 | return SerializerCode.valueOf("HESSION").getCode(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/JsonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.ncst.rpc.entity.RpcRequest; 6 | import com.ncst.rpc.enumeration.SerializerCode; 7 | import com.ncst.rpc.exception.SerializeException; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * 日拱一卒,不期速成 15 | * 16 | * @Auther: i 17 | * @Date: 2020/10/20/12:07 18 | * @Description: Json序列化 19 | */ 20 | public class JsonSerializer implements CommonSerializer { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(JsonSerializer.class); 23 | 24 | private ObjectMapper objectMapper = new ObjectMapper(); 25 | 26 | @Override 27 | public byte[] serialize(Object obj) { 28 | 29 | try { 30 | //obj序列化成字节数组 31 | return objectMapper.writeValueAsBytes(obj); 32 | } catch (JsonProcessingException e) { 33 | logger.error("...json序列化发生错误..."); 34 | throw new SerializeException("...序列化错误..."); 35 | } 36 | } 37 | 38 | @Override 39 | public Object deserialize(byte[] bytes, Class> clazz) { 40 | Object obj = null; 41 | try { 42 | obj = objectMapper.readValue(bytes, clazz); 43 | if (obj instanceof RpcRequest) { 44 | //拦截一下 45 | obj = handlerRequest(obj); 46 | } 47 | return obj; 48 | } catch (IOException e) { 49 | logger.error("...json反序列化发生错误..."); 50 | throw new SerializeException("..序列化错误..."); 51 | } 52 | } 53 | 54 | @Override 55 | public int getCode() { 56 | return SerializerCode.valueOf("JSON").getCode(); 57 | } 58 | 59 | //进行反序列化后无法还原真实对象 需要进行拦截处理 todo debug 60 | //总体思路 将obj进行转换一下 重新存储到rpcrequest 对象中 61 | private Object handlerRequest(Object obj) throws IOException { 62 | RpcRequest request = (RpcRequest) obj; 63 | for (int i = 0; i < request.getMethodTypes().length; i++) { 64 | //对应的类型 65 | Class> clazz = request.getMethodTypes()[i]; 66 | if (!clazz.isAssignableFrom(request.getParam()[i].getClass())) { 67 | byte[] bytes = objectMapper.writeValueAsBytes(request.getParam()[i]); 68 | request.getParam()[i] = objectMapper.readValue(bytes, clazz); 69 | } 70 | } 71 | return request; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/KryoSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.esotericsoftware.kryo.Kryo; 4 | import com.esotericsoftware.kryo.io.Input; 5 | import com.esotericsoftware.kryo.io.Output; 6 | import com.ncst.rpc.entity.RpcRequest; 7 | import com.ncst.rpc.entity.RpcResponse; 8 | import com.ncst.rpc.enumeration.SerializerCode; 9 | import com.ncst.rpc.exception.SerializeException; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.ByteArrayInputStream; 14 | import java.io.ByteArrayOutputStream; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/20/12:32 21 | * @Description: Kryo序列化 22 | */ 23 | public class KryoSerializer implements CommonSerializer { 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(KryoSerializer.class); 26 | 27 | //因为Kryo存在线程安全问题 需要存放到ThreadLocal中,需要的时候获取 不使用的时候remove; 28 | private static final ThreadLocal kryoThreadLocal = ThreadLocal.withInitial(() -> { 29 | Kryo kryo = new Kryo(); 30 | kryo.register(RpcRequest.class); 31 | kryo.register(RpcResponse.class); 32 | kryo.setReferences(true); 33 | kryo.setRegistrationRequired(false); 34 | return kryo; 35 | }); 36 | 37 | @Override 38 | public byte[] serialize(Object obj) { 39 | try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 40 | Output output = new Output(byteArrayOutputStream)) { 41 | Kryo kryo = kryoThreadLocal.get(); 42 | //将obj对象存储到kryo中 43 | kryo.writeObject(output, obj); 44 | kryoThreadLocal.remove(); 45 | //为什么删除 具体看threadlocal细节 46 | return output.toBytes(); 47 | } catch (Exception e) { 48 | logger.error("...Kryo序列化时出现错误..."); 49 | throw new SerializeException("...Kryo序列化时出现错误..."); 50 | } 51 | } 52 | 53 | @Override 54 | public Object deserialize(byte[] bytes, Class> clazz) { 55 | //反序列化操作 56 | try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); 57 | Input input = new Input(bis);) { 58 | Kryo kryo = kryoThreadLocal.get(); 59 | Object o = kryo.readObject(input, clazz); 60 | kryoThreadLocal.remove(); 61 | return o; 62 | } catch (Exception e) { 63 | logger.error("...Kryo反序列化时出现错误..."); 64 | throw new SerializeException("...Kryo反序列化时出现错误..."); 65 | } 66 | } 67 | 68 | @Override 69 | public int getCode() { 70 | return SerializerCode.valueOf("KRYO").getCode(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/ProtobufSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/20/13:03 8 | * @Description: 基于protobuf协议的序列化器 todo 9 | */ 10 | public class ProtobufSerializer implements CommonSerializer { 11 | 12 | @Override 13 | public byte[] serialize(Object obj) { 14 | return new byte[0]; 15 | } 16 | 17 | @Override 18 | public Object deserialize(byte[] bytes, Class> clazz) { 19 | return null; 20 | } 21 | 22 | @Override 23 | public int getCode() { 24 | return 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/AbstractRpcServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.annotation.ServiceScan; 5 | import com.ncst.provider.ServiceProvider; 6 | import com.ncst.registry.ServiceRegistry; 7 | import com.ncst.rpc.enumeration.RpcError; 8 | import com.ncst.rpc.exception.RpcException; 9 | import com.ncst.rpc.util.ReflectUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.net.InetSocketAddress; 14 | import java.util.Set; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/21/10:32 21 | * @Description: 抽象RPC服务基类 22 | */ 23 | public abstract class AbstractRpcServer implements RpcServer { 24 | 25 | protected static final Logger logger = LoggerFactory.getLogger(AbstractRpcServer.class); 26 | 27 | //ip地址 28 | protected String host; 29 | //port 30 | protected Integer port; 31 | 32 | //服务提供 33 | protected ServiceProvider serviceProvider; 34 | //服务注册 35 | protected ServiceRegistry serviceRegistry; 36 | 37 | /**** 38 | * 扫描带有Service的类 39 | */ 40 | public void scanServices() { 41 | //main方法所在类 42 | String mainClassName = ReflectUtil.getStackTrace(); 43 | Class> startClass = null; 44 | 45 | try { 46 | //加载类-main方法 47 | startClass = Class.forName(mainClassName); 48 | //如果注解上没有ServiceScan 49 | if (!startClass.isAnnotationPresent(ServiceScan.class)) { 50 | logger.error("...启动类缺少ServiecScan..."); 51 | throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_NOT_FOUND); 52 | } 53 | } catch (Exception e) { 54 | logger.error("...发生错误..."); 55 | throw new RpcException(RpcError.UNKNOWN_ERROR); 56 | } 57 | //获取扫描基础包 58 | String basePackage = startClass.getAnnotation(ServiceScan.class).value(); 59 | //如果等于"" 全扫描 截取类名 60 | if ("".equals(basePackage)) { 61 | basePackage = mainClassName.substring(0, mainClassName.lastIndexOf(".")); 62 | } 63 | 64 | //获取对应的类 65 | Set> classSet = ReflectUtil.getClasses(basePackage); 66 | //loop 67 | for (Class> clazz : classSet) { 68 | //获取被Service注解的类 69 | if (clazz.isAnnotationPresent(Service.class)) { 70 | //服务名 71 | String serviceName = clazz.getAnnotation(Service.class).name(); 72 | Object obj; 73 | try { 74 | obj = clazz.newInstance(); 75 | }catch (Exception e){ 76 | logger.error("创建"+clazz+"发生错误"); 77 | //如果当前出现错误 跳过 78 | continue; 79 | } 80 | if ("".equals(serviceName)) { 81 | Class> [] interfaces = clazz.getInterfaces(); 82 | for (Class> oneInterface : interfaces) { 83 | publicServer(obj,oneInterface.getCanonicalName()); 84 | } 85 | } else { 86 | //发布服务 87 | publicServer(obj,serviceName); 88 | } 89 | } 90 | } 91 | } 92 | 93 | /**** 94 | * 95 | * @param server 服务 96 | * @param serviceName 服务名 97 | * @param 98 | */ 99 | @Override 100 | public void publicServer(T server, String serviceName) { 101 | //服务提供 102 | serviceProvider.addServiceProvider(server, serviceName); 103 | //服务注册 104 | serviceRegistry.registry(serviceName, new InetSocketAddress(host, port)); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcClient.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.serializer.CommonSerializer; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/20/16:43 11 | * @Description: 客户端服务规范 12 | */ 13 | public interface RpcClient { 14 | 15 | /**** 16 | * 默认初始化方式 17 | */ 18 | int DEFAULT_SERIALIZER = CommonSerializer.KRYO_SERIALIZER; 19 | 20 | 21 | /**** 22 | * 23 | * @param rpcRequest 24 | * @return 25 | */ 26 | Object sendRequest (RpcRequest rpcRequest); 27 | } 28 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.util.RpcMessageChecker; 6 | import com.ncst.transport.client.NettyClient; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Proxy; 13 | import java.util.UUID; 14 | import java.util.concurrent.CompletableFuture; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/21/19:48 21 | * @Description: 客户端代理 22 | */ 23 | public class RpcClientProxy implements InvocationHandler { 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(RpcClientProxy.class); 26 | private final RpcClient rpcClient; 27 | 28 | public RpcClientProxy (RpcClient rpcClient) { 29 | this.rpcClient = rpcClient; 30 | } 31 | 32 | /***** 33 | * 生成代理类 34 | * @param clazz 35 | * @param 36 | * @return 37 | */ 38 | public T getProxy(Class clazz) { 39 | return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class>[]{clazz}, this::invoke); 40 | } 41 | 42 | /***** 43 | * 动态生成的类 一旦方法调用就触发invoke进行拦截处理 44 | * @param proxy 45 | * @param method 46 | * @param args 47 | * @return 48 | */ 49 | @Override 50 | public Object invoke(Object proxy, Method method, Object[] args) { 51 | logger.info("调用服务: {}-----{}", method.getDeclaringClass().getName(), method.getName()); 52 | //生成rpcRequest对象、id UUID、类名=服务名、方法名、参数、参数类型、是否心跳false 53 | RpcRequest rpcRequest = new RpcRequest(UUID.randomUUID().toString(), method.getDeclaringClass().getName(), 54 | method.getName(), args, method.getParameterTypes(), false); 55 | RpcResponse rpcResponse = null; 56 | //如果Netty形式 57 | if (rpcClient instanceof NettyClient) { 58 | try { 59 | //异步调用-发送数据给服务端 60 | CompletableFuture completableFuture = 61 | (CompletableFuture) rpcClient.sendRequest(rpcRequest); 62 | //异步获取数据 等待,如果必要的,为这个未来完成,然后返回其结果 63 | rpcResponse = completableFuture.get(); 64 | } catch (Exception e) { 65 | logger.error("方法调用请求发送失败", e); 66 | e.printStackTrace(); 67 | return null; 68 | } 69 | } 70 | //判断 71 | RpcMessageChecker.check(rpcRequest, rpcResponse); 72 | return rpcResponse.getData(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.serializer.CommonSerializer; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/19/18:12 10 | * @Description: 服务端接口规范 11 | */ 12 | public interface RpcServer { 13 | 14 | /**** 15 | * 默认序列化方式 16 | */ 17 | int DEFAULT_SERIAIIZER = CommonSerializer.KRYO_SERIALIZER; 18 | 19 | /**** 20 | * 启动 21 | */ 22 | void start (); 23 | 24 | /**** 25 | * 发布服务 26 | * @param server 服务 27 | * @param serviceName 服务名 28 | * @param 29 | */ 30 | void publicServer(T server,String serviceName); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/ChannelProvider.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.codec.CommoDecoder; 4 | import com.ncst.codec.CommonEncoder; 5 | import com.ncst.serializer.CommonSerializer; 6 | import io.netty.bootstrap.Bootstrap; 7 | import io.netty.channel.*; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | import io.netty.handler.timeout.IdleStateHandler; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.net.InetSocketAddress; 16 | import java.util.Map; 17 | import java.util.concurrent.CompletableFuture; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ExecutionException; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | /** 23 | * 日拱一卒,不期速成 24 | * 25 | * @Auther: i 26 | * @Date: 2020/10/21/16:29 27 | * @Description: 用于初始化对象 28 | */ 29 | public class ChannelProvider { 30 | 31 | private static final Logger logger = LoggerFactory.getLogger(ChannelProvider.class); 32 | private static EventLoopGroup eventLoopGroup; 33 | private static Bootstrap bootstrap = initBootStrap(); 34 | 35 | //key保存String Value保存Channel 36 | private static Map channels = new ConcurrentHashMap(); 37 | 38 | 39 | /**** 40 | * 41 | * @param socketAddress ip端口 42 | * @param serializer 序列化方式 43 | * @return 44 | */ 45 | public static Channel get(InetSocketAddress socketAddress, CommonSerializer serializer) { 46 | //ip+序列化方式 47 | String key = socketAddress.toString() + serializer.getCode(); 48 | // 49 | if (channels.containsKey(key)) { 50 | Channel channel = channels.get(key); 51 | if (channel != null && channel.isActive()) { 52 | return channel; 53 | } else { 54 | channels.remove(key); 55 | } 56 | } 57 | //拦截 58 | bootstrap.handler(new ChannelInitializer() { 59 | @Override 60 | protected void initChannel(SocketChannel ch) throws Exception { 61 | ChannelPipeline pipeline = ch.pipeline(); 62 | //编码 63 | pipeline.addLast(new CommonEncoder(serializer)) 64 | //心跳检测 65 | .addLast(new IdleStateHandler(0,5,0, TimeUnit.SECONDS)) 66 | //解码 67 | .addLast(new CommoDecoder()) 68 | //拦截器 69 | .addLast(new NettyClientHandler()); 70 | } 71 | }); 72 | Channel channel = null; 73 | try { 74 | channel = connect (bootstrap,socketAddress); 75 | }catch (Exception e) { 76 | logger.error("...连接客户端发生错误...",e); 77 | return null; 78 | } 79 | //存储到map中 80 | channels.put(key,channel); 81 | return channel; 82 | } 83 | 84 | /***** 85 | * 86 | * @param bootstrap 87 | * @param socketAddress 88 | * @return 89 | */ 90 | private static Channel connect(Bootstrap bootstrap, InetSocketAddress socketAddress) throws ExecutionException, InterruptedException { 91 | CompletableFuture completableFuture = new CompletableFuture<>(); 92 | bootstrap.connect(socketAddress).addListener((ChannelFutureListener) future -> { 93 | if (future.isSuccess()) { 94 | logger.info("...客户端连接成功..."); 95 | completableFuture.complete(future.channel()); 96 | } else { 97 | throw new IllegalAccessException(); 98 | } 99 | }); 100 | return completableFuture.get(); 101 | } 102 | 103 | /***** 104 | * 初始化bootStrap 105 | * @return 106 | */ 107 | public static Bootstrap initBootStrap() { 108 | eventLoopGroup = new NioEventLoopGroup(); 109 | Bootstrap bootstrap = new Bootstrap(); 110 | bootstrap.group(eventLoopGroup) 111 | .channel(NioSocketChannel.class) 112 | //连接的超时时间,超过这个时间还是建立不了的话 就代表连接失败, 113 | //如果15秒内没有发送数据给服务端的话,就发送一次心跳请求。 114 | .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) 115 | //开启TCP 底层心跳 116 | .option(ChannelOption.SO_KEEPALIVE, true) 117 | //TCP默认开启了 Nagle 算法,该算法的作用是尽可能的发送大数据快,减少网络传输。 118 | //TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。 119 | .option(ChannelOption.TCP_NODELAY, true); 120 | return bootstrap; 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.loadbalancer.LoadBalancer; 4 | import com.ncst.loadbalancer.RandomLoadBalancer; 5 | import com.ncst.loadbalancer.RoundRobinLoadBalancer; 6 | import com.ncst.registry.NacosServiceDiscovery; 7 | import com.ncst.registry.ServiceDiscovery; 8 | import com.ncst.rpc.entity.RpcRequest; 9 | import com.ncst.rpc.entity.RpcResponse; 10 | import com.ncst.rpc.enumeration.RpcError; 11 | import com.ncst.rpc.exception.RpcException; 12 | import com.ncst.rpc.factory.SingletonFactory; 13 | import com.ncst.serializer.CommonSerializer; 14 | import com.ncst.transport.RpcClient; 15 | import com.ncst.transport.server.NettyServer; 16 | import io.netty.bootstrap.Bootstrap; 17 | import io.netty.channel.Channel; 18 | import io.netty.channel.ChannelFutureListener; 19 | import io.netty.channel.EventLoopGroup; 20 | import io.netty.channel.nio.NioEventLoopGroup; 21 | import io.netty.channel.socket.nio.NioSocketChannel; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.net.InetSocketAddress; 26 | import java.util.concurrent.CompletableFuture; 27 | 28 | /** 29 | * 日拱一卒,不期速成 30 | * 31 | * @Auther: i 32 | * @Date: 2020/10/21/15:36 33 | * @Description: Netty客户端 34 | */ 35 | public class NettyClient implements RpcClient { 36 | 37 | private static final Logger logger = LoggerFactory.getLogger(NettyServer.class); 38 | 39 | private static final EventLoopGroup workGroup; 40 | private static final Bootstrap bootStrap; 41 | 42 | static { 43 | workGroup = new NioEventLoopGroup(); 44 | bootStrap = new Bootstrap(); 45 | bootStrap.group(workGroup) 46 | .channel(NioSocketChannel.class); 47 | } 48 | 49 | private UnprocessedRequests unprocessedRequests; 50 | private CommonSerializer commonSerializer; 51 | private ServiceDiscovery serviceDiscovery; 52 | private LoadBalancer loadBalancer; 53 | 54 | 55 | public NettyClient() { 56 | this(DEFAULT_SERIALIZER, new RandomLoadBalancer()); 57 | } 58 | 59 | //默认随机负载 60 | public NettyClient(int serializerCode) { 61 | this(serializerCode, new RoundRobinLoadBalancer()); 62 | } 63 | 64 | //自定义负载 65 | public NettyClient(LoadBalancer loadBalancer) { 66 | this(DEFAULT_SERIALIZER, loadBalancer); 67 | } 68 | 69 | public NettyClient(int serializerCode, LoadBalancer loadBalancer) { 70 | commonSerializer = CommonSerializer.getBytes(serializerCode); 71 | unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class); 72 | serviceDiscovery = new NacosServiceDiscovery(loadBalancer); 73 | } 74 | 75 | /**** 76 | * 客户端发送数据 77 | * @param rpcRequest 78 | * @return 79 | */ 80 | @Override 81 | public CompletableFuture sendRequest(RpcRequest rpcRequest) { 82 | if (commonSerializer == null) { 83 | logger.error("【...没有序列化...】"); 84 | throw new RpcException(RpcError.SERIALIZER_NOT_FOUND); 85 | } 86 | CompletableFuture resultFuture = new CompletableFuture<>(); 87 | try { 88 | //根据服务名查询某一个台服务 89 | InetSocketAddress inetSocketAddress = serviceDiscovery.lookUpService(rpcRequest.getInterfaceName()); 90 | //根据ip信息和序列化方式查找通道 91 | Channel channel = ChannelProvider.get(inetSocketAddress, commonSerializer); 92 | //如果通道没有激活 直接关闭 93 | if (!channel.isActive()) { 94 | workGroup.shutdownGracefully(); 95 | return null; 96 | } 97 | //存放未处理的请求 98 | unprocessedRequests.put(rpcRequest.getId(), resultFuture); 99 | //将数据写入到通道里 并设置一个监听器 100 | channel.writeAndFlush(rpcRequest).addListener((ChannelFutureListener) future -> { 101 | if (future.isSuccess()) { 102 | logger.info(String.format("【客户端发送消息: %s】", rpcRequest.toString())); 103 | } else { 104 | future.channel().close(); 105 | resultFuture.completeExceptionally(future.cause()); 106 | logger.error("【发送消息时有错误发生: 】", future.cause()); 107 | } 108 | }); 109 | 110 | } catch (Exception e) { 111 | unprocessedRequests.remove(rpcRequest.getId()); 112 | logger.error(e.getMessage(), e); 113 | Thread.currentThread().interrupt(); 114 | } 115 | return resultFuture; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.factory.SingletonFactory; 6 | import com.ncst.serializer.CommonSerializer; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelFutureListener; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | import io.netty.util.ReferenceCountUtil; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.net.InetSocketAddress; 18 | 19 | /** 20 | * 日拱一卒,不期速成 21 | * 22 | * @Auther: i 23 | * @Date: 2020/10/21/16:04 24 | * @Description: 25 | */ 26 | public class NettyClientHandler extends SimpleChannelInboundHandler { 27 | 28 | private static final Logger logger = LoggerFactory.getLogger(NettyClientHandler.class); 29 | 30 | private final UnprocessedRequests unprocessedRequests; 31 | 32 | public NettyClientHandler() { 33 | unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class); 34 | } 35 | 36 | @Override 37 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse msg) throws Exception { 38 | try { 39 | logger.info("...接收到服务端的消息..." + msg); 40 | unprocessedRequests.complete(msg); 41 | } finally { 42 | ReferenceCountUtil.release(msg); 43 | } 44 | } 45 | 46 | /**** 47 | * 异常处理 48 | * @param ctx 49 | * @param cause 50 | * @throws Exception 51 | */ 52 | @Override 53 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 54 | logger.error("...发生了异常..."); 55 | cause.printStackTrace(); 56 | ctx.close(); 57 | } 58 | 59 | /**** 60 | * 心跳处理 61 | * @param ctx 62 | * @param evt 63 | * @throws Exception 64 | */ 65 | @Override 66 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 67 | //如果属于心跳事件 则处理 68 | if (evt instanceof IdleStateEvent) { 69 | IdleState state = ((IdleStateEvent) evt).state(); 70 | //发送读心跳事件 71 | if (state == IdleState.WRITER_IDLE) { 72 | logger.info("---发送心跳包---" + ctx.channel().remoteAddress()); 73 | Channel channel = ChannelProvider.get((InetSocketAddress) ctx.channel().remoteAddress(), CommonSerializer.getBytes(CommonSerializer.DEFAULT_SERIALIZER)); 74 | RpcRequest rpcRequest = new RpcRequest(); 75 | //设置心跳 76 | rpcRequest.setHeartBeat(true); 77 | channel.writeAndFlush(rpcRequest).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); 78 | } 79 | } else { 80 | super.userEventTriggered(ctx, evt); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/UnprocessedRequests.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.rpc.entity.RpcResponse; 4 | import com.ncst.rpc.enumeration.RpcError; 5 | import com.ncst.rpc.exception.RpcException; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/21/15:23 17 | * @Description: key为requestId value为future 存放未处理的请求 18 | */ 19 | public class UnprocessedRequests { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(UnprocessedRequests.class); 22 | private static ConcurrentHashMap> unprocessedMap = 23 | new ConcurrentHashMap<>(); 24 | 25 | /**** 26 | * 存储 27 | * @param requestId 28 | * @param future 29 | */ 30 | public void put (String requestId , CompletableFuture future) { 31 | try { 32 | unprocessedMap.put(requestId,future); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | /*** 39 | * 删除 40 | * @param requestId 41 | */ 42 | public void remove (String requestId) { 43 | unprocessedMap.remove(requestId); 44 | } 45 | 46 | /**** 47 | * 48 | * @param rpcResponse 49 | */ 50 | public void complete (RpcResponse rpcResponse) { 51 | CompletableFuture future = unprocessedMap.remove(rpcResponse.getRequestId()); 52 | if (future != null) { 53 | future.complete(rpcResponse); 54 | } else { 55 | logger.error("...rpc not complete..."); 56 | throw new RpcException(RpcError.UNKNOWN_ERROR); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.server; 2 | 3 | import com.ncst.codec.CommoDecoder; 4 | import com.ncst.codec.CommonEncoder; 5 | import com.ncst.hook.ShutDownHook; 6 | import com.ncst.provider.ServiceProviderImpl; 7 | import com.ncst.registry.NacosServiceRegistry; 8 | import com.ncst.serializer.CommonSerializer; 9 | import com.ncst.transport.AbstractRpcServer; 10 | import io.netty.bootstrap.ServerBootstrap; 11 | import io.netty.channel.*; 12 | import io.netty.channel.nio.NioEventLoopGroup; 13 | import io.netty.channel.socket.SocketChannel; 14 | import io.netty.channel.socket.nio.NioServerSocketChannel; 15 | import io.netty.handler.logging.LogLevel; 16 | import io.netty.handler.logging.LoggingHandler; 17 | import io.netty.handler.timeout.IdleStateHandler; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * 日拱一卒,不期速成 25 | * 26 | * @Auther: i 27 | * @Date: 2020/10/21/11:32 28 | * @Description: Netty服务器 29 | */ 30 | public class NettyServer extends AbstractRpcServer { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(NettyServer.class); 33 | private CommonSerializer commonSerializer; 34 | 35 | public NettyServer (String host,int port) { 36 | this(host,port,DEFAULT_SERIAIIZER); 37 | } 38 | 39 | public NettyServer(String host, int port, int defaultSeriaiizer) { 40 | this.host = host; 41 | this.port = port; 42 | //服务提供者 43 | serviceProvider = new ServiceProviderImpl(); 44 | //服务注册者 45 | serviceRegistry = new NacosServiceRegistry(); 46 | //默认序列化方式 47 | this.commonSerializer = CommonSerializer.getBytes(defaultSeriaiizer); 48 | 49 | //扫描服务ScanService Scan 50 | scanServices(); 51 | } 52 | 53 | @Override 54 | public void start() { 55 | //钩子 清除所有实例 56 | ShutDownHook.getInstance().clearAllService(); 57 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 58 | EventLoopGroup workGroup = new NioEventLoopGroup(); 59 | 60 | try { 61 | ServerBootstrap bootstrap = new ServerBootstrap(); 62 | bootstrap.group(bossGroup,workGroup) 63 | .channel(NioServerSocketChannel.class) 64 | .handler(new LoggingHandler(LogLevel.INFO))//log日志 65 | //初始化可连接服务端队列大小,同一时间可以处理的客户端连接数 66 | .option(ChannelOption.SO_BACKLOG,256) 67 | //开启server端Tcp Keepalive 68 | .option(ChannelOption.SO_KEEPALIVE,true) 69 | //tcp不延时 70 | .childOption(ChannelOption.TCP_NODELAY,true) 71 | .childHandler(new ChannelInitializer() { 72 | @Override 73 | protected void initChannel(SocketChannel ch) throws Exception { 74 | ChannelPipeline pipeline = ch.pipeline(); 75 | //IdleStsteHandler Netty提供的处理空闲状态的处理器 76 | //readerIdleTime : 30S没有读 就发送一个心跳检测包看是否连接 77 | //writerIdleTime : 0S没有写就发送一个心跳检测包看是否连接 78 | //alldleTime : 0S 没有读写发送一个心跳检测包是否连接 79 | pipeline.addLast(new IdleStateHandler(300,0,0, TimeUnit.SECONDS)) 80 | //编码器 81 | .addLast(new CommonEncoder(commonSerializer)) 82 | //解码器 83 | .addLast(new CommoDecoder()) 84 | //过滤器 85 | .addLast(new NettyServerHandler()); 86 | 87 | } 88 | }); 89 | 90 | //关闭 91 | ChannelFuture future = bootstrap.bind(host,port).sync(); 92 | future.channel().closeFuture().sync(); 93 | } catch (Exception e) { 94 | logger.error("【...服务器关闭时出现错误...】"); 95 | e.printStackTrace(); 96 | } finally { 97 | //释放资源 98 | bossGroup.shutdownGracefully(); 99 | workGroup.shutdownGracefully(); 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.server; 2 | 3 | import com.ncst.handler.RequestHandler; 4 | import com.ncst.rpc.entity.RpcRequest; 5 | import com.ncst.rpc.entity.RpcResponse; 6 | import com.ncst.rpc.factory.SingletonFactory; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.SimpleChannelInboundHandler; 9 | import io.netty.handler.timeout.IdleState; 10 | import io.netty.handler.timeout.IdleStateEvent; 11 | import io.netty.util.ReferenceCountUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * 日拱一卒,不期速成 17 | * 18 | * @Auther: i 19 | * @Date: 2020/10/21/14:48 20 | * @Description: Netty中处理的RpcRequest的Handler 21 | * 因为SimpleChannelInboundHandler继承ChannelInboundHandlerAdapter 22 | * 就可以处理入站数据处理的应用容器 23 | */ 24 | public class NettyServerHandler extends SimpleChannelInboundHandler { 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); 27 | private RequestHandler requestHandler; 28 | 29 | 30 | public NettyServerHandler () { 31 | //生成一个单实例 32 | this.requestHandler = SingletonFactory.getInstance(RequestHandler.class); 33 | } 34 | 35 | /**** 36 | * 读取客户端数据 37 | * @param ctx 38 | * @param rpcRequest 39 | * @throws Exception 40 | */ 41 | @Override 42 | protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception { 43 | try { 44 | if (rpcRequest.isHeartBeat()) { 45 | logger.info("【---接收到客户端心跳包 ---】"); 46 | return; 47 | } 48 | 49 | System.out.println("【...服务器收到请求...】 "+rpcRequest.toString()); 50 | 51 | //处理数据请求 52 | Object result = requestHandler.handle(rpcRequest); 53 | if (ctx.channel().isActive() && ctx.channel().isWritable()) { 54 | ctx.writeAndFlush(RpcResponse.success(result,rpcRequest.getId())); 55 | } else { 56 | logger.error("【...通道不可写...】"); 57 | } 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } finally { 61 | // todo 62 | ReferenceCountUtil.release(rpcRequest); 63 | } 64 | 65 | } 66 | 67 | /***** 68 | * 异常处理 69 | * @param ctx 70 | * @param cause 71 | * @throws Exception 72 | */ 73 | @Override 74 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 75 | logger.error("【...处理过程调用时有错误发生...】"); 76 | cause.printStackTrace(); 77 | ctx.close(); 78 | } 79 | 80 | 81 | /**** 82 | * 开启心跳机制后,如果连接后的时间太长,将会触发一个IdleStateEvent事件。 83 | * 重写userEventTriggered 可以处理该事件 84 | * @param ctx 85 | * @param evt 86 | * @throws Exception 87 | */ 88 | @Override 89 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 90 | //心跳检测 如果属于IdelStateEvent事件 91 | if (evt instanceof IdleStateEvent) { 92 | IdleState state = ((IdleStateEvent) evt).state(); 93 | //未收到读事件 94 | if (state == IdleState.READER_IDLE) { 95 | logger.info("【...长时间未收到心跳包,断开连接...】"); 96 | ctx.close(); 97 | } 98 | } else { 99 | super.userEventTriggered(ctx,ctx); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | test-client 13 | 14 | 15 | 16 | 17 | com.ncst 18 | rpc-api 19 | 1.0-SNAPSHOT 20 | 21 | 22 | 23 | com.ncst 24 | rpc-core 25 | 1.0-SNAPSHOT 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test-client/src/main/java/NettyTestClient.java: -------------------------------------------------------------------------------- 1 | import com.ncst.api.ByeService; 2 | import com.ncst.api.DataObject; 3 | import com.ncst.api.HelloService; 4 | import com.ncst.serializer.CommonSerializer; 5 | import com.ncst.transport.RpcClient; 6 | import com.ncst.transport.RpcClientProxy; 7 | import com.ncst.transport.client.NettyClient; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/21/20:00 14 | * @Description: 15 | */ 16 | public class NettyTestClient { 17 | 18 | public static void main(String[] args) { 19 | //创建客户端+序列化 20 | RpcClient client = new NettyClient(CommonSerializer.DEFAULT_SERIALIZER); 21 | //代理 22 | RpcClientProxy rpcClientProxy = new RpcClientProxy(client); 23 | //生成代理类 24 | HelloService proxy = rpcClientProxy.getProxy(HelloService.class); 25 | //代理类调用 26 | String hello = proxy.hello(new DataObject(1,"【 客户端:】你好 ")); 27 | 28 | System.out.println("【 服务端回响数据 】"+hello); 29 | 30 | ByeService bye = rpcClientProxy.getProxy(ByeService.class); 31 | 32 | System.out.println(bye.bye("【 客户端:】再见 ")); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | test-server 13 | 14 | 15 | 16 | com.ncst 17 | rpc-api 18 | 1.0-SNAPSHOT 19 | compile 20 | 21 | 22 | 23 | com.ncst 24 | rpc-core 25 | 1.0-SNAPSHOT 26 | compile 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/ByeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.api.ByeService; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/21/17:20 11 | * @Description: 12 | */ 13 | @Service 14 | public class ByeServiceImpl implements ByeService { 15 | 16 | @Override 17 | public String bye(String name) { 18 | return "【 服务端:】 再见"+name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.api.DataObject; 5 | import com.ncst.api.HelloService; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/21/17:21 14 | * @Description: 15 | */ 16 | @Service 17 | public class HelloServiceImpl implements HelloService { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(HelloService.class); 20 | 21 | @Override 22 | public String hello(DataObject object) { 23 | System.out.println("【...接收到消息...】"+object.getMessage()); 24 | return "...服务端回应...你好..."; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/NettyTestServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.ServiceScan; 4 | import com.ncst.serializer.CommonSerializer; 5 | import com.ncst.transport.RpcServer; 6 | import com.ncst.transport.server.NettyServer; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/21/17:24 13 | * @Description: Netty服务提供者 服务端 14 | */ 15 | @ServiceScan 16 | public class NettyTestServer { 17 | 18 | /***** 19 | * 数据流转向 20 | * 1.注解扫描 21 | * 2.发布服务 22 | * @param args 23 | */ 24 | public static void main(String[] args) { 25 | RpcServer rpcServer = new NettyServer("127.0.0.1",9998, CommonSerializer.DEFAULT_SERIALIZER); 26 | rpcServer.start(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test-server/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG,stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n --------------------------------------------------------------------------------
19 | * 魔数+包类型+序列化类型+data 20 | * 继承MessageToByteEncoder转换成Byte数组,将请求或响应包装成响应包。 21 | */ 22 | public class CommonEncoder extends MessageToByteEncoder { 23 | 24 | //魔数 25 | private static final int MAGIC_NUMBER = 0xCAFEBABE; 26 | 27 | private CommonSerializer commonSerializer; 28 | 29 | public CommonEncoder(CommonSerializer commonSerializer) { 30 | this.commonSerializer = commonSerializer; 31 | } 32 | 33 | /****** 34 | * 因为编码器对于客户端和服务端都会调用,因此需要进行区分,也就是通过数据包的类型来判断request response 35 | * @param ctx 36 | * @param msg 37 | * @param byteBuf 38 | * @throws Exception 39 | */ 40 | @Override 41 | protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf byteBuf) throws Exception { 42 | byteBuf.writeInt(MAGIC_NUMBER);//魔数 43 | //request 44 | if (msg instanceof RpcRequest) { 45 | byteBuf.writeInt(PackageType.REQUEST_PACK.getCode()); 46 | //response 47 | } else { 48 | byteBuf.writeInt(PackageType.RESPONSE_PACK.getCode()); 49 | } 50 | //序列化方式 51 | byteBuf.writeInt(commonSerializer.getCode()); 52 | byte[] bytes = commonSerializer.serialize(msg);//序列化 53 | byteBuf.writeInt(bytes.length);//length 54 | byteBuf.writeBytes(bytes);//data 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/handler/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.handler; 2 | 3 | import com.ncst.provider.ServiceProvider; 4 | import com.ncst.provider.ServiceProviderImpl; 5 | import com.ncst.rpc.entity.RpcRequest; 6 | import com.ncst.rpc.entity.RpcResponse; 7 | import com.ncst.rpc.enumeration.ResponseCode; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | * 日拱一卒,不期速成 15 | * 16 | * @Auther: i 17 | * @Date: 2020/10/20/18:05 18 | * @Description: 进程过程调用的处理器 19 | */ 20 | public class RequestHandler { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class); 23 | 24 | private static ServiceProvider serviceProcider = null; 25 | 26 | static { 27 | serviceProcider = new ServiceProviderImpl(); 28 | } 29 | 30 | //拦截器 获取rpcRequest请求 31 | public Object handle(RpcRequest rpcRequest) { 32 | //以接口为一个服务 33 | Object service = serviceProcider.getServiceProvider(rpcRequest.getInterfaceName()); 34 | return invokeTargetMethod(rpcRequest, service); 35 | } 36 | 37 | private Object invokeTargetMethod(RpcRequest rpcRequest, Object service) { 38 | Object result = null; 39 | try { 40 | //返回一个 方法对象反映的类或接口的 类对象表示的指定公共成员方法。 41 | //类名 42 | //方法类型 todo 43 | Method method = service.getClass().getMethod(rpcRequest.getMethodName(), rpcRequest.getMethodTypes()); 44 | //todo ? 是调用 45 | result = method.invoke(service, rpcRequest.getParam()); 46 | System.out.println("【 服务 】"+rpcRequest.getInterfaceName()+"【 调用方法 】"+ rpcRequest.getMethodName()); 47 | } catch (Exception e) { 48 | return RpcResponse.fail(ResponseCode.METHOD_NOT_FOUND, rpcRequest.getId()); 49 | } 50 | return result; 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/hook/ShutDownHook.java: -------------------------------------------------------------------------------- 1 | package com.ncst.hook; 2 | 3 | import com.ncst.rpc.factory.ThreadPoolFactory; 4 | import com.ncst.rpc.util.NacosUtil; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/20/18:00 13 | * @Description: 14 | */ 15 | public class ShutDownHook { 16 | 17 | private static final Logger logger = LoggerFactory.getLogger(ShutDownHook.class); 18 | 19 | private static final ShutDownHook shutDownHook = new ShutDownHook(); 20 | 21 | private ShutDownHook () { 22 | 23 | } 24 | 25 | public static ShutDownHook getInstance () { 26 | return shutDownHook; 27 | } 28 | 29 | /**** 30 | * 当系统关闭之前 调用 将所有注册的服务进行删除。否则下一次启动 客户端 31 | * 会调用只有名字而没有服务的实例,出现错误 32 | */ 33 | public void clearAllService () { 34 | logger.info("...关闭所有服务..."); 35 | Runtime.getRuntime().addShutdownHook(new Thread(() -> { 36 | NacosUtil.clearRegistry(); 37 | ThreadPoolFactory.shutDownAll(); 38 | })); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/LoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 日拱一卒,不期速成 9 | * 10 | * @Auther: i 11 | * @Date: 2020/10/20/17:23 12 | * @Description: 负载策略 13 | */ 14 | public interface LoadBalancer { 15 | 16 | /**** 17 | * 获取实例 18 | * @param list 19 | * @return 20 | */ 21 | Instance selectForInstance (List list); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/RandomLoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/20/17:25 13 | * @Description: 随机策略 14 | */ 15 | public class RandomLoadBalancer implements LoadBalancer { 16 | 17 | @Override 18 | public Instance selectForInstance(List list) { 19 | return list.get(new Random().nextInt(list.size())); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/loadbalancer/RoundRobinLoadBalancer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.loadbalancer; 2 | 3 | import com.alibaba.nacos.api.naming.pojo.Instance; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 日拱一卒,不期速成 9 | * 10 | * @Auther: i 11 | * @Date: 2020/10/20/17:27 12 | * @Description: 轮询策略 13 | */ 14 | public class RoundRobinLoadBalancer implements LoadBalancer{ 15 | 16 | private int index = 0; 17 | 18 | @Override 19 | public Instance selectForInstance(List list) { 20 | System.out.println(list); 21 | if (index >= list.size()) { 22 | index %= list.size() ; 23 | } 24 | return list.get(index++); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/provider/ServiceProvider.java: -------------------------------------------------------------------------------- 1 | package com.ncst.provider; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/20/16:52 8 | * @Description: 添加服务实例者 9 | */ 10 | public interface ServiceProvider { 11 | 12 | /**** 13 | * 添加服务实例 14 | * @param service 15 | * @param serviceName 16 | * @param 17 | */ 18 | void addServiceProvider(T service, String serviceName); 19 | 20 | 21 | /*** 22 | * 根据服务实例获取服务 23 | * @param serviceName 24 | * @return 25 | */ 26 | Object getServiceProvider(String serviceName); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/provider/ServiceProviderImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.provider; 2 | 3 | import com.ncst.rpc.enumeration.RpcError; 4 | import com.ncst.rpc.exception.RpcException; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/20/17:00 17 | * @Description: 将用户注册的服务存储到Map中 用Map的key记录那些服务已经被注册了 18 | */ 19 | public class ServiceProviderImpl implements ServiceProvider { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(ServiceProviderImpl.class); 22 | 23 | //key存储服务名 value存储服务实例 24 | private static final Map serviceMap = new ConcurrentHashMap<>(); 25 | //存储服务名 26 | private static final Set registeredService = ConcurrentHashMap.newKeySet(); 27 | 28 | @Override 29 | public void addServiceProvider(T service, String serviceName) { 30 | if (service == null || serviceName == null) return; 31 | //存在 32 | if (registeredService.contains(serviceName)) return; 33 | try { 34 | registeredService.add(serviceName); 35 | serviceMap.put(serviceName,service); 36 | logger.info("接口: {} 注册服务: {}",service,serviceName); 37 | } catch (Exception e) { 38 | logger.error("...服务注册过程中失败..."); 39 | } 40 | } 41 | 42 | @Override 43 | public Object getServiceProvider(String serviceName) { 44 | Object o = serviceMap.get(serviceName); 45 | if (o == null) { 46 | throw new RpcException(RpcError.SERVICE_NOT_FOUND); 47 | } 48 | return o; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/NacosServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import com.alibaba.nacos.api.exception.NacosException; 4 | import com.alibaba.nacos.api.naming.pojo.Instance; 5 | import com.ncst.loadbalancer.LoadBalancer; 6 | import com.ncst.loadbalancer.RandomLoadBalancer; 7 | import com.ncst.rpc.enumeration.RpcError; 8 | import com.ncst.rpc.exception.RpcException; 9 | import com.ncst.rpc.util.NacosUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.net.InetSocketAddress; 14 | import java.util.List; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/20/17:33 21 | * @Description: Nacos服务发现 用于客户端调用 22 | */ 23 | public class NacosServiceDiscovery implements ServiceDiscovery{ 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); 26 | 27 | private static LoadBalancer loadBalancer; 28 | 29 | //默认随机负载 30 | public NacosServiceDiscovery (LoadBalancer loadBalancer) { 31 | if (loadBalancer == null) { 32 | loadBalancer = new RandomLoadBalancer(); 33 | } else { 34 | this.loadBalancer = loadBalancer; 35 | } 36 | } 37 | 38 | /***** 39 | * 根据服务名获取服务器-根据不同的策略跳转 40 | * @param serviceName 41 | * @return 42 | */ 43 | @Override 44 | public InetSocketAddress lookUpService(String serviceName) { 45 | try { 46 | List instanceList = NacosUtil.getAllInstance(serviceName); 47 | if (instanceList.size() == 0) { 48 | logger.error("...找不到服务实例..."+serviceName); 49 | throw new RpcException(RpcError.SERVICE_NOT_FOUND); 50 | } 51 | Instance instance = loadBalancer.selectForInstance(instanceList); 52 | return new InetSocketAddress(instance.getIp(),instance.getPort()); 53 | } catch (NacosException e) { 54 | logger.info("...获取服务失败..."); 55 | } 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/NacosServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import com.alibaba.nacos.api.exception.NacosException; 4 | import com.ncst.rpc.enumeration.RpcError; 5 | import com.ncst.rpc.exception.RpcException; 6 | import com.ncst.rpc.util.NacosUtil; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.net.InetSocketAddress; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/20/17:16 17 | * @Description: Nacos服务注册 18 | */ 19 | public class NacosServiceRegistry implements ServiceRegistry{ 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class); 22 | 23 | @Override 24 | public void registry(String serviceName, InetSocketAddress inetSocketAddress) { 25 | try { 26 | //util工具类 27 | NacosUtil.registerService(serviceName,inetSocketAddress); 28 | } catch (NacosException e) { 29 | logger.error("...注册服务时发生错误..."); 30 | throw new RpcException(RpcError.REGISTER_SERVICE_FAILED); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/ServiceDiscovery.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/20/17:19 10 | * @Description: 服务发现接口 11 | */ 12 | public interface ServiceDiscovery { 13 | 14 | 15 | /**** 16 | * 通过服务名查找 17 | * @param serviceName 18 | * @return 19 | */ 20 | InetSocketAddress lookUpService (String serviceName); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/registry/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.ncst.registry; 2 | 3 | import java.net.InetSocketAddress; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/20/17:12 10 | * @Description: 服务注册 11 | */ 12 | public interface ServiceRegistry { 13 | 14 | /**** 15 | * 服务注册 16 | * @param serviceName 服务名称 17 | * @param inetSocketAddress ip地址 18 | */ 19 | void registry (String serviceName, InetSocketAddress inetSocketAddress); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/CommonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/19/18:13 8 | * @Description: 通用的序列化反序列化接口 9 | */ 10 | public interface CommonSerializer { 11 | 12 | Integer KRYO_SERIALIZER = 0; 13 | Integer JSON_SERIALIZER = 1; 14 | Integer HESSION_SERIALIZER = 2; 15 | Integer PROTOBUF_SERIALIZER = 3; 16 | 17 | Integer DEFAULT_SERIALIZER = KRYO_SERIALIZER; 18 | 19 | static CommonSerializer getBytes (int code) { 20 | switch (code) { 21 | case 0 : 22 | return new KryoSerializer(); 23 | case 1: 24 | return new JsonSerializer(); 25 | case 2: 26 | return new HessianSerializer(); 27 | case 3: 28 | return new ProtobufSerializer(); 29 | default: 30 | return null; 31 | } 32 | } 33 | 34 | /*** 35 | * 序列化 将obj 36 | * @param obj 37 | * @return 38 | */ 39 | byte [] serialize (Object obj); 40 | 41 | /**** 42 | * 反序列化 43 | * @param bytes 44 | * @param clazz 45 | * @return 46 | */ 47 | Object deserialize (byte [] bytes,Class> clazz); 48 | 49 | /**** 50 | * 序列化器编号 51 | * @return 52 | */ 53 | int getCode(); 54 | 55 | } 56 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/HessianSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.caucho.hessian.io.HessianInput; 4 | import com.caucho.hessian.io.HessianOutput; 5 | import com.ncst.rpc.enumeration.SerializerCode; 6 | import com.ncst.rpc.exception.SerializeException; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.io.ByteArrayInputStream; 11 | import java.io.ByteArrayOutputStream; 12 | import java.io.IOException; 13 | 14 | /** 15 | * 日拱一卒,不期速成 16 | * 17 | * @Auther: i 18 | * @Date: 2020/10/20/13:02 19 | * @Description: 基于Hession协议的序列化器 20 | */ 21 | public class HessianSerializer implements CommonSerializer{ 22 | 23 | private static final Logger logger = LoggerFactory.getLogger(HessianSerializer.class); 24 | 25 | @Override 26 | public byte[] serialize(Object obj) { 27 | HessianOutput hessianOutput = null; 28 | //输出 29 | try (ByteArrayOutputStream baos = new ByteArrayOutputStream()){ 30 | hessianOutput = new HessianOutput(baos); 31 | hessianOutput.writeObject(obj); 32 | return baos.toByteArray(); 33 | } catch (Exception e) { 34 | logger.error("...hession序列化发生错误..."); 35 | throw new SerializeException("...hession序列化发生错误..."); 36 | } finally { 37 | if (hessianOutput != null) { 38 | try { 39 | hessianOutput.close(); 40 | } catch (IOException e) { 41 | logger.error("...hession关闭流发生错误..."); 42 | } 43 | } 44 | } 45 | } 46 | 47 | @Override 48 | public Object deserialize(byte[] bytes, Class> clazz) { 49 | HessianInput hessianOutput = null; 50 | try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { 51 | hessianOutput = new HessianInput(bais); 52 | return hessianOutput.readObject(clazz); 53 | } catch (Exception e) { 54 | logger.error("...hession反序列化发生错误..."); 55 | } finally { 56 | if (hessianOutput != null) { 57 | try { 58 | hessianOutput.close(); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | } 64 | return null; 65 | } 66 | 67 | @Override 68 | public int getCode() { 69 | return SerializerCode.valueOf("HESSION").getCode(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/JsonSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.ncst.rpc.entity.RpcRequest; 6 | import com.ncst.rpc.enumeration.SerializerCode; 7 | import com.ncst.rpc.exception.SerializeException; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import java.io.IOException; 12 | 13 | /** 14 | * 日拱一卒,不期速成 15 | * 16 | * @Auther: i 17 | * @Date: 2020/10/20/12:07 18 | * @Description: Json序列化 19 | */ 20 | public class JsonSerializer implements CommonSerializer { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(JsonSerializer.class); 23 | 24 | private ObjectMapper objectMapper = new ObjectMapper(); 25 | 26 | @Override 27 | public byte[] serialize(Object obj) { 28 | 29 | try { 30 | //obj序列化成字节数组 31 | return objectMapper.writeValueAsBytes(obj); 32 | } catch (JsonProcessingException e) { 33 | logger.error("...json序列化发生错误..."); 34 | throw new SerializeException("...序列化错误..."); 35 | } 36 | } 37 | 38 | @Override 39 | public Object deserialize(byte[] bytes, Class> clazz) { 40 | Object obj = null; 41 | try { 42 | obj = objectMapper.readValue(bytes, clazz); 43 | if (obj instanceof RpcRequest) { 44 | //拦截一下 45 | obj = handlerRequest(obj); 46 | } 47 | return obj; 48 | } catch (IOException e) { 49 | logger.error("...json反序列化发生错误..."); 50 | throw new SerializeException("..序列化错误..."); 51 | } 52 | } 53 | 54 | @Override 55 | public int getCode() { 56 | return SerializerCode.valueOf("JSON").getCode(); 57 | } 58 | 59 | //进行反序列化后无法还原真实对象 需要进行拦截处理 todo debug 60 | //总体思路 将obj进行转换一下 重新存储到rpcrequest 对象中 61 | private Object handlerRequest(Object obj) throws IOException { 62 | RpcRequest request = (RpcRequest) obj; 63 | for (int i = 0; i < request.getMethodTypes().length; i++) { 64 | //对应的类型 65 | Class> clazz = request.getMethodTypes()[i]; 66 | if (!clazz.isAssignableFrom(request.getParam()[i].getClass())) { 67 | byte[] bytes = objectMapper.writeValueAsBytes(request.getParam()[i]); 68 | request.getParam()[i] = objectMapper.readValue(bytes, clazz); 69 | } 70 | } 71 | return request; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/KryoSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | import com.esotericsoftware.kryo.Kryo; 4 | import com.esotericsoftware.kryo.io.Input; 5 | import com.esotericsoftware.kryo.io.Output; 6 | import com.ncst.rpc.entity.RpcRequest; 7 | import com.ncst.rpc.entity.RpcResponse; 8 | import com.ncst.rpc.enumeration.SerializerCode; 9 | import com.ncst.rpc.exception.SerializeException; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.ByteArrayInputStream; 14 | import java.io.ByteArrayOutputStream; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/20/12:32 21 | * @Description: Kryo序列化 22 | */ 23 | public class KryoSerializer implements CommonSerializer { 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(KryoSerializer.class); 26 | 27 | //因为Kryo存在线程安全问题 需要存放到ThreadLocal中,需要的时候获取 不使用的时候remove; 28 | private static final ThreadLocal kryoThreadLocal = ThreadLocal.withInitial(() -> { 29 | Kryo kryo = new Kryo(); 30 | kryo.register(RpcRequest.class); 31 | kryo.register(RpcResponse.class); 32 | kryo.setReferences(true); 33 | kryo.setRegistrationRequired(false); 34 | return kryo; 35 | }); 36 | 37 | @Override 38 | public byte[] serialize(Object obj) { 39 | try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 40 | Output output = new Output(byteArrayOutputStream)) { 41 | Kryo kryo = kryoThreadLocal.get(); 42 | //将obj对象存储到kryo中 43 | kryo.writeObject(output, obj); 44 | kryoThreadLocal.remove(); 45 | //为什么删除 具体看threadlocal细节 46 | return output.toBytes(); 47 | } catch (Exception e) { 48 | logger.error("...Kryo序列化时出现错误..."); 49 | throw new SerializeException("...Kryo序列化时出现错误..."); 50 | } 51 | } 52 | 53 | @Override 54 | public Object deserialize(byte[] bytes, Class> clazz) { 55 | //反序列化操作 56 | try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); 57 | Input input = new Input(bis);) { 58 | Kryo kryo = kryoThreadLocal.get(); 59 | Object o = kryo.readObject(input, clazz); 60 | kryoThreadLocal.remove(); 61 | return o; 62 | } catch (Exception e) { 63 | logger.error("...Kryo反序列化时出现错误..."); 64 | throw new SerializeException("...Kryo反序列化时出现错误..."); 65 | } 66 | } 67 | 68 | @Override 69 | public int getCode() { 70 | return SerializerCode.valueOf("KRYO").getCode(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/serializer/ProtobufSerializer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.serializer; 2 | 3 | /** 4 | * 日拱一卒,不期速成 5 | * 6 | * @Auther: i 7 | * @Date: 2020/10/20/13:03 8 | * @Description: 基于protobuf协议的序列化器 todo 9 | */ 10 | public class ProtobufSerializer implements CommonSerializer { 11 | 12 | @Override 13 | public byte[] serialize(Object obj) { 14 | return new byte[0]; 15 | } 16 | 17 | @Override 18 | public Object deserialize(byte[] bytes, Class> clazz) { 19 | return null; 20 | } 21 | 22 | @Override 23 | public int getCode() { 24 | return 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/AbstractRpcServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.annotation.ServiceScan; 5 | import com.ncst.provider.ServiceProvider; 6 | import com.ncst.registry.ServiceRegistry; 7 | import com.ncst.rpc.enumeration.RpcError; 8 | import com.ncst.rpc.exception.RpcException; 9 | import com.ncst.rpc.util.ReflectUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.net.InetSocketAddress; 14 | import java.util.Set; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/21/10:32 21 | * @Description: 抽象RPC服务基类 22 | */ 23 | public abstract class AbstractRpcServer implements RpcServer { 24 | 25 | protected static final Logger logger = LoggerFactory.getLogger(AbstractRpcServer.class); 26 | 27 | //ip地址 28 | protected String host; 29 | //port 30 | protected Integer port; 31 | 32 | //服务提供 33 | protected ServiceProvider serviceProvider; 34 | //服务注册 35 | protected ServiceRegistry serviceRegistry; 36 | 37 | /**** 38 | * 扫描带有Service的类 39 | */ 40 | public void scanServices() { 41 | //main方法所在类 42 | String mainClassName = ReflectUtil.getStackTrace(); 43 | Class> startClass = null; 44 | 45 | try { 46 | //加载类-main方法 47 | startClass = Class.forName(mainClassName); 48 | //如果注解上没有ServiceScan 49 | if (!startClass.isAnnotationPresent(ServiceScan.class)) { 50 | logger.error("...启动类缺少ServiecScan..."); 51 | throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_NOT_FOUND); 52 | } 53 | } catch (Exception e) { 54 | logger.error("...发生错误..."); 55 | throw new RpcException(RpcError.UNKNOWN_ERROR); 56 | } 57 | //获取扫描基础包 58 | String basePackage = startClass.getAnnotation(ServiceScan.class).value(); 59 | //如果等于"" 全扫描 截取类名 60 | if ("".equals(basePackage)) { 61 | basePackage = mainClassName.substring(0, mainClassName.lastIndexOf(".")); 62 | } 63 | 64 | //获取对应的类 65 | Set> classSet = ReflectUtil.getClasses(basePackage); 66 | //loop 67 | for (Class> clazz : classSet) { 68 | //获取被Service注解的类 69 | if (clazz.isAnnotationPresent(Service.class)) { 70 | //服务名 71 | String serviceName = clazz.getAnnotation(Service.class).name(); 72 | Object obj; 73 | try { 74 | obj = clazz.newInstance(); 75 | }catch (Exception e){ 76 | logger.error("创建"+clazz+"发生错误"); 77 | //如果当前出现错误 跳过 78 | continue; 79 | } 80 | if ("".equals(serviceName)) { 81 | Class> [] interfaces = clazz.getInterfaces(); 82 | for (Class> oneInterface : interfaces) { 83 | publicServer(obj,oneInterface.getCanonicalName()); 84 | } 85 | } else { 86 | //发布服务 87 | publicServer(obj,serviceName); 88 | } 89 | } 90 | } 91 | } 92 | 93 | /**** 94 | * 95 | * @param server 服务 96 | * @param serviceName 服务名 97 | * @param 98 | */ 99 | @Override 100 | public void publicServer(T server, String serviceName) { 101 | //服务提供 102 | serviceProvider.addServiceProvider(server, serviceName); 103 | //服务注册 104 | serviceRegistry.registry(serviceName, new InetSocketAddress(host, port)); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcClient.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.serializer.CommonSerializer; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/20/16:43 11 | * @Description: 客户端服务规范 12 | */ 13 | public interface RpcClient { 14 | 15 | /**** 16 | * 默认初始化方式 17 | */ 18 | int DEFAULT_SERIALIZER = CommonSerializer.KRYO_SERIALIZER; 19 | 20 | 21 | /**** 22 | * 23 | * @param rpcRequest 24 | * @return 25 | */ 26 | Object sendRequest (RpcRequest rpcRequest); 27 | } 28 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcClientProxy.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.util.RpcMessageChecker; 6 | import com.ncst.transport.client.NettyClient; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Proxy; 13 | import java.util.UUID; 14 | import java.util.concurrent.CompletableFuture; 15 | 16 | /** 17 | * 日拱一卒,不期速成 18 | * 19 | * @Auther: i 20 | * @Date: 2020/10/21/19:48 21 | * @Description: 客户端代理 22 | */ 23 | public class RpcClientProxy implements InvocationHandler { 24 | 25 | private static final Logger logger = LoggerFactory.getLogger(RpcClientProxy.class); 26 | private final RpcClient rpcClient; 27 | 28 | public RpcClientProxy (RpcClient rpcClient) { 29 | this.rpcClient = rpcClient; 30 | } 31 | 32 | /***** 33 | * 生成代理类 34 | * @param clazz 35 | * @param 36 | * @return 37 | */ 38 | public T getProxy(Class clazz) { 39 | return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class>[]{clazz}, this::invoke); 40 | } 41 | 42 | /***** 43 | * 动态生成的类 一旦方法调用就触发invoke进行拦截处理 44 | * @param proxy 45 | * @param method 46 | * @param args 47 | * @return 48 | */ 49 | @Override 50 | public Object invoke(Object proxy, Method method, Object[] args) { 51 | logger.info("调用服务: {}-----{}", method.getDeclaringClass().getName(), method.getName()); 52 | //生成rpcRequest对象、id UUID、类名=服务名、方法名、参数、参数类型、是否心跳false 53 | RpcRequest rpcRequest = new RpcRequest(UUID.randomUUID().toString(), method.getDeclaringClass().getName(), 54 | method.getName(), args, method.getParameterTypes(), false); 55 | RpcResponse rpcResponse = null; 56 | //如果Netty形式 57 | if (rpcClient instanceof NettyClient) { 58 | try { 59 | //异步调用-发送数据给服务端 60 | CompletableFuture completableFuture = 61 | (CompletableFuture) rpcClient.sendRequest(rpcRequest); 62 | //异步获取数据 等待,如果必要的,为这个未来完成,然后返回其结果 63 | rpcResponse = completableFuture.get(); 64 | } catch (Exception e) { 65 | logger.error("方法调用请求发送失败", e); 66 | e.printStackTrace(); 67 | return null; 68 | } 69 | } 70 | //判断 71 | RpcMessageChecker.check(rpcRequest, rpcResponse); 72 | return rpcResponse.getData(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/RpcServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport; 2 | 3 | import com.ncst.serializer.CommonSerializer; 4 | 5 | /** 6 | * 日拱一卒,不期速成 7 | * 8 | * @Auther: i 9 | * @Date: 2020/10/19/18:12 10 | * @Description: 服务端接口规范 11 | */ 12 | public interface RpcServer { 13 | 14 | /**** 15 | * 默认序列化方式 16 | */ 17 | int DEFAULT_SERIAIIZER = CommonSerializer.KRYO_SERIALIZER; 18 | 19 | /**** 20 | * 启动 21 | */ 22 | void start (); 23 | 24 | /**** 25 | * 发布服务 26 | * @param server 服务 27 | * @param serviceName 服务名 28 | * @param 29 | */ 30 | void publicServer(T server,String serviceName); 31 | 32 | } 33 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/ChannelProvider.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.codec.CommoDecoder; 4 | import com.ncst.codec.CommonEncoder; 5 | import com.ncst.serializer.CommonSerializer; 6 | import io.netty.bootstrap.Bootstrap; 7 | import io.netty.channel.*; 8 | import io.netty.channel.nio.NioEventLoopGroup; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioSocketChannel; 11 | import io.netty.handler.timeout.IdleStateHandler; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | import java.net.InetSocketAddress; 16 | import java.util.Map; 17 | import java.util.concurrent.CompletableFuture; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.ExecutionException; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | /** 23 | * 日拱一卒,不期速成 24 | * 25 | * @Auther: i 26 | * @Date: 2020/10/21/16:29 27 | * @Description: 用于初始化对象 28 | */ 29 | public class ChannelProvider { 30 | 31 | private static final Logger logger = LoggerFactory.getLogger(ChannelProvider.class); 32 | private static EventLoopGroup eventLoopGroup; 33 | private static Bootstrap bootstrap = initBootStrap(); 34 | 35 | //key保存String Value保存Channel 36 | private static Map channels = new ConcurrentHashMap(); 37 | 38 | 39 | /**** 40 | * 41 | * @param socketAddress ip端口 42 | * @param serializer 序列化方式 43 | * @return 44 | */ 45 | public static Channel get(InetSocketAddress socketAddress, CommonSerializer serializer) { 46 | //ip+序列化方式 47 | String key = socketAddress.toString() + serializer.getCode(); 48 | // 49 | if (channels.containsKey(key)) { 50 | Channel channel = channels.get(key); 51 | if (channel != null && channel.isActive()) { 52 | return channel; 53 | } else { 54 | channels.remove(key); 55 | } 56 | } 57 | //拦截 58 | bootstrap.handler(new ChannelInitializer() { 59 | @Override 60 | protected void initChannel(SocketChannel ch) throws Exception { 61 | ChannelPipeline pipeline = ch.pipeline(); 62 | //编码 63 | pipeline.addLast(new CommonEncoder(serializer)) 64 | //心跳检测 65 | .addLast(new IdleStateHandler(0,5,0, TimeUnit.SECONDS)) 66 | //解码 67 | .addLast(new CommoDecoder()) 68 | //拦截器 69 | .addLast(new NettyClientHandler()); 70 | } 71 | }); 72 | Channel channel = null; 73 | try { 74 | channel = connect (bootstrap,socketAddress); 75 | }catch (Exception e) { 76 | logger.error("...连接客户端发生错误...",e); 77 | return null; 78 | } 79 | //存储到map中 80 | channels.put(key,channel); 81 | return channel; 82 | } 83 | 84 | /***** 85 | * 86 | * @param bootstrap 87 | * @param socketAddress 88 | * @return 89 | */ 90 | private static Channel connect(Bootstrap bootstrap, InetSocketAddress socketAddress) throws ExecutionException, InterruptedException { 91 | CompletableFuture completableFuture = new CompletableFuture<>(); 92 | bootstrap.connect(socketAddress).addListener((ChannelFutureListener) future -> { 93 | if (future.isSuccess()) { 94 | logger.info("...客户端连接成功..."); 95 | completableFuture.complete(future.channel()); 96 | } else { 97 | throw new IllegalAccessException(); 98 | } 99 | }); 100 | return completableFuture.get(); 101 | } 102 | 103 | /***** 104 | * 初始化bootStrap 105 | * @return 106 | */ 107 | public static Bootstrap initBootStrap() { 108 | eventLoopGroup = new NioEventLoopGroup(); 109 | Bootstrap bootstrap = new Bootstrap(); 110 | bootstrap.group(eventLoopGroup) 111 | .channel(NioSocketChannel.class) 112 | //连接的超时时间,超过这个时间还是建立不了的话 就代表连接失败, 113 | //如果15秒内没有发送数据给服务端的话,就发送一次心跳请求。 114 | .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) 115 | //开启TCP 底层心跳 116 | .option(ChannelOption.SO_KEEPALIVE, true) 117 | //TCP默认开启了 Nagle 算法,该算法的作用是尽可能的发送大数据快,减少网络传输。 118 | //TCP_NODELAY 参数的作用就是控制是否启用 Nagle 算法。 119 | .option(ChannelOption.TCP_NODELAY, true); 120 | return bootstrap; 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/NettyClient.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.loadbalancer.LoadBalancer; 4 | import com.ncst.loadbalancer.RandomLoadBalancer; 5 | import com.ncst.loadbalancer.RoundRobinLoadBalancer; 6 | import com.ncst.registry.NacosServiceDiscovery; 7 | import com.ncst.registry.ServiceDiscovery; 8 | import com.ncst.rpc.entity.RpcRequest; 9 | import com.ncst.rpc.entity.RpcResponse; 10 | import com.ncst.rpc.enumeration.RpcError; 11 | import com.ncst.rpc.exception.RpcException; 12 | import com.ncst.rpc.factory.SingletonFactory; 13 | import com.ncst.serializer.CommonSerializer; 14 | import com.ncst.transport.RpcClient; 15 | import com.ncst.transport.server.NettyServer; 16 | import io.netty.bootstrap.Bootstrap; 17 | import io.netty.channel.Channel; 18 | import io.netty.channel.ChannelFutureListener; 19 | import io.netty.channel.EventLoopGroup; 20 | import io.netty.channel.nio.NioEventLoopGroup; 21 | import io.netty.channel.socket.nio.NioSocketChannel; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.net.InetSocketAddress; 26 | import java.util.concurrent.CompletableFuture; 27 | 28 | /** 29 | * 日拱一卒,不期速成 30 | * 31 | * @Auther: i 32 | * @Date: 2020/10/21/15:36 33 | * @Description: Netty客户端 34 | */ 35 | public class NettyClient implements RpcClient { 36 | 37 | private static final Logger logger = LoggerFactory.getLogger(NettyServer.class); 38 | 39 | private static final EventLoopGroup workGroup; 40 | private static final Bootstrap bootStrap; 41 | 42 | static { 43 | workGroup = new NioEventLoopGroup(); 44 | bootStrap = new Bootstrap(); 45 | bootStrap.group(workGroup) 46 | .channel(NioSocketChannel.class); 47 | } 48 | 49 | private UnprocessedRequests unprocessedRequests; 50 | private CommonSerializer commonSerializer; 51 | private ServiceDiscovery serviceDiscovery; 52 | private LoadBalancer loadBalancer; 53 | 54 | 55 | public NettyClient() { 56 | this(DEFAULT_SERIALIZER, new RandomLoadBalancer()); 57 | } 58 | 59 | //默认随机负载 60 | public NettyClient(int serializerCode) { 61 | this(serializerCode, new RoundRobinLoadBalancer()); 62 | } 63 | 64 | //自定义负载 65 | public NettyClient(LoadBalancer loadBalancer) { 66 | this(DEFAULT_SERIALIZER, loadBalancer); 67 | } 68 | 69 | public NettyClient(int serializerCode, LoadBalancer loadBalancer) { 70 | commonSerializer = CommonSerializer.getBytes(serializerCode); 71 | unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class); 72 | serviceDiscovery = new NacosServiceDiscovery(loadBalancer); 73 | } 74 | 75 | /**** 76 | * 客户端发送数据 77 | * @param rpcRequest 78 | * @return 79 | */ 80 | @Override 81 | public CompletableFuture sendRequest(RpcRequest rpcRequest) { 82 | if (commonSerializer == null) { 83 | logger.error("【...没有序列化...】"); 84 | throw new RpcException(RpcError.SERIALIZER_NOT_FOUND); 85 | } 86 | CompletableFuture resultFuture = new CompletableFuture<>(); 87 | try { 88 | //根据服务名查询某一个台服务 89 | InetSocketAddress inetSocketAddress = serviceDiscovery.lookUpService(rpcRequest.getInterfaceName()); 90 | //根据ip信息和序列化方式查找通道 91 | Channel channel = ChannelProvider.get(inetSocketAddress, commonSerializer); 92 | //如果通道没有激活 直接关闭 93 | if (!channel.isActive()) { 94 | workGroup.shutdownGracefully(); 95 | return null; 96 | } 97 | //存放未处理的请求 98 | unprocessedRequests.put(rpcRequest.getId(), resultFuture); 99 | //将数据写入到通道里 并设置一个监听器 100 | channel.writeAndFlush(rpcRequest).addListener((ChannelFutureListener) future -> { 101 | if (future.isSuccess()) { 102 | logger.info(String.format("【客户端发送消息: %s】", rpcRequest.toString())); 103 | } else { 104 | future.channel().close(); 105 | resultFuture.completeExceptionally(future.cause()); 106 | logger.error("【发送消息时有错误发生: 】", future.cause()); 107 | } 108 | }); 109 | 110 | } catch (Exception e) { 111 | unprocessedRequests.remove(rpcRequest.getId()); 112 | logger.error(e.getMessage(), e); 113 | Thread.currentThread().interrupt(); 114 | } 115 | return resultFuture; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/NettyClientHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.rpc.entity.RpcRequest; 4 | import com.ncst.rpc.entity.RpcResponse; 5 | import com.ncst.rpc.factory.SingletonFactory; 6 | import com.ncst.serializer.CommonSerializer; 7 | import io.netty.channel.Channel; 8 | import io.netty.channel.ChannelFutureListener; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import io.netty.channel.SimpleChannelInboundHandler; 11 | import io.netty.handler.timeout.IdleState; 12 | import io.netty.handler.timeout.IdleStateEvent; 13 | import io.netty.util.ReferenceCountUtil; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import java.net.InetSocketAddress; 18 | 19 | /** 20 | * 日拱一卒,不期速成 21 | * 22 | * @Auther: i 23 | * @Date: 2020/10/21/16:04 24 | * @Description: 25 | */ 26 | public class NettyClientHandler extends SimpleChannelInboundHandler { 27 | 28 | private static final Logger logger = LoggerFactory.getLogger(NettyClientHandler.class); 29 | 30 | private final UnprocessedRequests unprocessedRequests; 31 | 32 | public NettyClientHandler() { 33 | unprocessedRequests = SingletonFactory.getInstance(UnprocessedRequests.class); 34 | } 35 | 36 | @Override 37 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse msg) throws Exception { 38 | try { 39 | logger.info("...接收到服务端的消息..." + msg); 40 | unprocessedRequests.complete(msg); 41 | } finally { 42 | ReferenceCountUtil.release(msg); 43 | } 44 | } 45 | 46 | /**** 47 | * 异常处理 48 | * @param ctx 49 | * @param cause 50 | * @throws Exception 51 | */ 52 | @Override 53 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 54 | logger.error("...发生了异常..."); 55 | cause.printStackTrace(); 56 | ctx.close(); 57 | } 58 | 59 | /**** 60 | * 心跳处理 61 | * @param ctx 62 | * @param evt 63 | * @throws Exception 64 | */ 65 | @Override 66 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 67 | //如果属于心跳事件 则处理 68 | if (evt instanceof IdleStateEvent) { 69 | IdleState state = ((IdleStateEvent) evt).state(); 70 | //发送读心跳事件 71 | if (state == IdleState.WRITER_IDLE) { 72 | logger.info("---发送心跳包---" + ctx.channel().remoteAddress()); 73 | Channel channel = ChannelProvider.get((InetSocketAddress) ctx.channel().remoteAddress(), CommonSerializer.getBytes(CommonSerializer.DEFAULT_SERIALIZER)); 74 | RpcRequest rpcRequest = new RpcRequest(); 75 | //设置心跳 76 | rpcRequest.setHeartBeat(true); 77 | channel.writeAndFlush(rpcRequest).addListener(ChannelFutureListener.CLOSE_ON_FAILURE); 78 | } 79 | } else { 80 | super.userEventTriggered(ctx, evt); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/client/UnprocessedRequests.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.client; 2 | 3 | import com.ncst.rpc.entity.RpcResponse; 4 | import com.ncst.rpc.enumeration.RpcError; 5 | import com.ncst.rpc.exception.RpcException; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | /** 13 | * 日拱一卒,不期速成 14 | * 15 | * @Auther: i 16 | * @Date: 2020/10/21/15:23 17 | * @Description: key为requestId value为future 存放未处理的请求 18 | */ 19 | public class UnprocessedRequests { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(UnprocessedRequests.class); 22 | private static ConcurrentHashMap> unprocessedMap = 23 | new ConcurrentHashMap<>(); 24 | 25 | /**** 26 | * 存储 27 | * @param requestId 28 | * @param future 29 | */ 30 | public void put (String requestId , CompletableFuture future) { 31 | try { 32 | unprocessedMap.put(requestId,future); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | /*** 39 | * 删除 40 | * @param requestId 41 | */ 42 | public void remove (String requestId) { 43 | unprocessedMap.remove(requestId); 44 | } 45 | 46 | /**** 47 | * 48 | * @param rpcResponse 49 | */ 50 | public void complete (RpcResponse rpcResponse) { 51 | CompletableFuture future = unprocessedMap.remove(rpcResponse.getRequestId()); 52 | if (future != null) { 53 | future.complete(rpcResponse); 54 | } else { 55 | logger.error("...rpc not complete..."); 56 | throw new RpcException(RpcError.UNKNOWN_ERROR); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/server/NettyServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.server; 2 | 3 | import com.ncst.codec.CommoDecoder; 4 | import com.ncst.codec.CommonEncoder; 5 | import com.ncst.hook.ShutDownHook; 6 | import com.ncst.provider.ServiceProviderImpl; 7 | import com.ncst.registry.NacosServiceRegistry; 8 | import com.ncst.serializer.CommonSerializer; 9 | import com.ncst.transport.AbstractRpcServer; 10 | import io.netty.bootstrap.ServerBootstrap; 11 | import io.netty.channel.*; 12 | import io.netty.channel.nio.NioEventLoopGroup; 13 | import io.netty.channel.socket.SocketChannel; 14 | import io.netty.channel.socket.nio.NioServerSocketChannel; 15 | import io.netty.handler.logging.LogLevel; 16 | import io.netty.handler.logging.LoggingHandler; 17 | import io.netty.handler.timeout.IdleStateHandler; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | /** 24 | * 日拱一卒,不期速成 25 | * 26 | * @Auther: i 27 | * @Date: 2020/10/21/11:32 28 | * @Description: Netty服务器 29 | */ 30 | public class NettyServer extends AbstractRpcServer { 31 | 32 | private static final Logger logger = LoggerFactory.getLogger(NettyServer.class); 33 | private CommonSerializer commonSerializer; 34 | 35 | public NettyServer (String host,int port) { 36 | this(host,port,DEFAULT_SERIAIIZER); 37 | } 38 | 39 | public NettyServer(String host, int port, int defaultSeriaiizer) { 40 | this.host = host; 41 | this.port = port; 42 | //服务提供者 43 | serviceProvider = new ServiceProviderImpl(); 44 | //服务注册者 45 | serviceRegistry = new NacosServiceRegistry(); 46 | //默认序列化方式 47 | this.commonSerializer = CommonSerializer.getBytes(defaultSeriaiizer); 48 | 49 | //扫描服务ScanService Scan 50 | scanServices(); 51 | } 52 | 53 | @Override 54 | public void start() { 55 | //钩子 清除所有实例 56 | ShutDownHook.getInstance().clearAllService(); 57 | EventLoopGroup bossGroup = new NioEventLoopGroup(); 58 | EventLoopGroup workGroup = new NioEventLoopGroup(); 59 | 60 | try { 61 | ServerBootstrap bootstrap = new ServerBootstrap(); 62 | bootstrap.group(bossGroup,workGroup) 63 | .channel(NioServerSocketChannel.class) 64 | .handler(new LoggingHandler(LogLevel.INFO))//log日志 65 | //初始化可连接服务端队列大小,同一时间可以处理的客户端连接数 66 | .option(ChannelOption.SO_BACKLOG,256) 67 | //开启server端Tcp Keepalive 68 | .option(ChannelOption.SO_KEEPALIVE,true) 69 | //tcp不延时 70 | .childOption(ChannelOption.TCP_NODELAY,true) 71 | .childHandler(new ChannelInitializer() { 72 | @Override 73 | protected void initChannel(SocketChannel ch) throws Exception { 74 | ChannelPipeline pipeline = ch.pipeline(); 75 | //IdleStsteHandler Netty提供的处理空闲状态的处理器 76 | //readerIdleTime : 30S没有读 就发送一个心跳检测包看是否连接 77 | //writerIdleTime : 0S没有写就发送一个心跳检测包看是否连接 78 | //alldleTime : 0S 没有读写发送一个心跳检测包是否连接 79 | pipeline.addLast(new IdleStateHandler(300,0,0, TimeUnit.SECONDS)) 80 | //编码器 81 | .addLast(new CommonEncoder(commonSerializer)) 82 | //解码器 83 | .addLast(new CommoDecoder()) 84 | //过滤器 85 | .addLast(new NettyServerHandler()); 86 | 87 | } 88 | }); 89 | 90 | //关闭 91 | ChannelFuture future = bootstrap.bind(host,port).sync(); 92 | future.channel().closeFuture().sync(); 93 | } catch (Exception e) { 94 | logger.error("【...服务器关闭时出现错误...】"); 95 | e.printStackTrace(); 96 | } finally { 97 | //释放资源 98 | bossGroup.shutdownGracefully(); 99 | workGroup.shutdownGracefully(); 100 | } 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /rpc-core/src/main/java/com/ncst/transport/server/NettyServerHandler.java: -------------------------------------------------------------------------------- 1 | package com.ncst.transport.server; 2 | 3 | import com.ncst.handler.RequestHandler; 4 | import com.ncst.rpc.entity.RpcRequest; 5 | import com.ncst.rpc.entity.RpcResponse; 6 | import com.ncst.rpc.factory.SingletonFactory; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.SimpleChannelInboundHandler; 9 | import io.netty.handler.timeout.IdleState; 10 | import io.netty.handler.timeout.IdleStateEvent; 11 | import io.netty.util.ReferenceCountUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * 日拱一卒,不期速成 17 | * 18 | * @Auther: i 19 | * @Date: 2020/10/21/14:48 20 | * @Description: Netty中处理的RpcRequest的Handler 21 | * 因为SimpleChannelInboundHandler继承ChannelInboundHandlerAdapter 22 | * 就可以处理入站数据处理的应用容器 23 | */ 24 | public class NettyServerHandler extends SimpleChannelInboundHandler { 25 | 26 | private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class); 27 | private RequestHandler requestHandler; 28 | 29 | 30 | public NettyServerHandler () { 31 | //生成一个单实例 32 | this.requestHandler = SingletonFactory.getInstance(RequestHandler.class); 33 | } 34 | 35 | /**** 36 | * 读取客户端数据 37 | * @param ctx 38 | * @param rpcRequest 39 | * @throws Exception 40 | */ 41 | @Override 42 | protected void channelRead0(ChannelHandlerContext ctx, RpcRequest rpcRequest) throws Exception { 43 | try { 44 | if (rpcRequest.isHeartBeat()) { 45 | logger.info("【---接收到客户端心跳包 ---】"); 46 | return; 47 | } 48 | 49 | System.out.println("【...服务器收到请求...】 "+rpcRequest.toString()); 50 | 51 | //处理数据请求 52 | Object result = requestHandler.handle(rpcRequest); 53 | if (ctx.channel().isActive() && ctx.channel().isWritable()) { 54 | ctx.writeAndFlush(RpcResponse.success(result,rpcRequest.getId())); 55 | } else { 56 | logger.error("【...通道不可写...】"); 57 | } 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } finally { 61 | // todo 62 | ReferenceCountUtil.release(rpcRequest); 63 | } 64 | 65 | } 66 | 67 | /***** 68 | * 异常处理 69 | * @param ctx 70 | * @param cause 71 | * @throws Exception 72 | */ 73 | @Override 74 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 75 | logger.error("【...处理过程调用时有错误发生...】"); 76 | cause.printStackTrace(); 77 | ctx.close(); 78 | } 79 | 80 | 81 | /**** 82 | * 开启心跳机制后,如果连接后的时间太长,将会触发一个IdleStateEvent事件。 83 | * 重写userEventTriggered 可以处理该事件 84 | * @param ctx 85 | * @param evt 86 | * @throws Exception 87 | */ 88 | @Override 89 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 90 | //心跳检测 如果属于IdelStateEvent事件 91 | if (evt instanceof IdleStateEvent) { 92 | IdleState state = ((IdleStateEvent) evt).state(); 93 | //未收到读事件 94 | if (state == IdleState.READER_IDLE) { 95 | logger.info("【...长时间未收到心跳包,断开连接...】"); 96 | ctx.close(); 97 | } 98 | } else { 99 | super.userEventTriggered(ctx,ctx); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /test-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | test-client 13 | 14 | 15 | 16 | 17 | com.ncst 18 | rpc-api 19 | 1.0-SNAPSHOT 20 | 21 | 22 | 23 | com.ncst 24 | rpc-core 25 | 1.0-SNAPSHOT 26 | compile 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test-client/src/main/java/NettyTestClient.java: -------------------------------------------------------------------------------- 1 | import com.ncst.api.ByeService; 2 | import com.ncst.api.DataObject; 3 | import com.ncst.api.HelloService; 4 | import com.ncst.serializer.CommonSerializer; 5 | import com.ncst.transport.RpcClient; 6 | import com.ncst.transport.RpcClientProxy; 7 | import com.ncst.transport.client.NettyClient; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/21/20:00 14 | * @Description: 15 | */ 16 | public class NettyTestClient { 17 | 18 | public static void main(String[] args) { 19 | //创建客户端+序列化 20 | RpcClient client = new NettyClient(CommonSerializer.DEFAULT_SERIALIZER); 21 | //代理 22 | RpcClientProxy rpcClientProxy = new RpcClientProxy(client); 23 | //生成代理类 24 | HelloService proxy = rpcClientProxy.getProxy(HelloService.class); 25 | //代理类调用 26 | String hello = proxy.hello(new DataObject(1,"【 客户端:】你好 ")); 27 | 28 | System.out.println("【 服务端回响数据 】"+hello); 29 | 30 | ByeService bye = rpcClientProxy.getProxy(ByeService.class); 31 | 32 | System.out.println(bye.bye("【 客户端:】再见 ")); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /test-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | RPC-Framework 7 | com.ncst 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | test-server 13 | 14 | 15 | 16 | com.ncst 17 | rpc-api 18 | 1.0-SNAPSHOT 19 | compile 20 | 21 | 22 | 23 | com.ncst 24 | rpc-core 25 | 1.0-SNAPSHOT 26 | compile 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/ByeServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.api.ByeService; 5 | 6 | /** 7 | * 日拱一卒,不期速成 8 | * 9 | * @Auther: i 10 | * @Date: 2020/10/21/17:20 11 | * @Description: 12 | */ 13 | @Service 14 | public class ByeServiceImpl implements ByeService { 15 | 16 | @Override 17 | public String bye(String name) { 18 | return "【 服务端:】 再见"+name; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.Service; 4 | import com.ncst.api.DataObject; 5 | import com.ncst.api.HelloService; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * 日拱一卒,不期速成 11 | * 12 | * @Auther: i 13 | * @Date: 2020/10/21/17:21 14 | * @Description: 15 | */ 16 | @Service 17 | public class HelloServiceImpl implements HelloService { 18 | 19 | private static final Logger logger = LoggerFactory.getLogger(HelloService.class); 20 | 21 | @Override 22 | public String hello(DataObject object) { 23 | System.out.println("【...接收到消息...】"+object.getMessage()); 24 | return "...服务端回应...你好..."; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test-server/src/main/java/com/ncst/nettyserver/NettyTestServer.java: -------------------------------------------------------------------------------- 1 | package com.ncst.nettyserver; 2 | 3 | import com.ncst.annotation.ServiceScan; 4 | import com.ncst.serializer.CommonSerializer; 5 | import com.ncst.transport.RpcServer; 6 | import com.ncst.transport.server.NettyServer; 7 | 8 | /** 9 | * 日拱一卒,不期速成 10 | * 11 | * @Auther: i 12 | * @Date: 2020/10/21/17:24 13 | * @Description: Netty服务提供者 服务端 14 | */ 15 | @ServiceScan 16 | public class NettyTestServer { 17 | 18 | /***** 19 | * 数据流转向 20 | * 1.注解扫描 21 | * 2.发布服务 22 | * @param args 23 | */ 24 | public static void main(String[] args) { 25 | RpcServer rpcServer = new NettyServer("127.0.0.1",9998, CommonSerializer.DEFAULT_SERIALIZER); 26 | rpcServer.start(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test-server/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=DEBUG,stdout 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.stdout.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n --------------------------------------------------------------------------------