├── .gitignore ├── HEADER ├── LICENSE ├── README.md ├── client ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── github │ │ └── liyue2008 │ │ └── rpc │ │ └── client │ │ └── Client.java │ └── test │ └── RealSubject.java ├── hello-service-api ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── liyue2008 │ └── rpc │ └── hello │ ├── HelloService.java │ └── entity │ ├── HelloRequest.java │ └── HelloResult.java ├── pom.xml ├── rpc-api ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── liyue2008 │ └── rpc │ ├── NameService.java │ ├── RpcAccessPoint.java │ └── spi │ ├── ServiceLoadException.java │ ├── ServiceSupport.java │ └── Singleton.java ├── rpc-netty ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── liyue2008 │ │ └── rpc │ │ ├── NettyRpcAccessPoint.java │ │ ├── client │ │ ├── CGLibDynamicProxy.java │ │ ├── CGLibDynamicStubFactory.java │ │ ├── DynamicStubFactory.java │ │ ├── RequestIdSupport.java │ │ ├── ServiceStub.java │ │ ├── ServiceTypes.java │ │ ├── StubFactory.java │ │ └── stubs │ │ │ ├── AbstractStub.java │ │ │ └── RpcRequest.java │ │ ├── nameservice │ │ ├── LocalFileNameService.java │ │ └── Metadata.java │ │ ├── serialize │ │ ├── SerializeException.java │ │ ├── SerializeSupport.java │ │ ├── Serializer.java │ │ └── impl │ │ │ ├── MetadataSerializer.java │ │ │ ├── ObjectArraysSerializer.java │ │ │ ├── ObjectSerializer.java │ │ │ ├── RpcRequestSerializer.java │ │ │ ├── StringSerializer.java │ │ │ └── Types.java │ │ ├── server │ │ ├── RpcRequestHandler.java │ │ └── ServiceProviderRegistry.java │ │ └── transport │ │ ├── InFlightRequests.java │ │ ├── RequestHandler.java │ │ ├── RequestHandlerRegistry.java │ │ ├── ResponseFuture.java │ │ ├── Transport.java │ │ ├── TransportClient.java │ │ ├── TransportServer.java │ │ ├── command │ │ ├── Code.java │ │ ├── Command.java │ │ ├── Header.java │ │ └── ResponseHeader.java │ │ └── netty │ │ ├── CommandDecoder.java │ │ ├── CommandEncoder.java │ │ ├── NettyClient.java │ │ ├── NettyServer.java │ │ ├── NettyTransport.java │ │ ├── RequestDecoder.java │ │ ├── RequestEncoder.java │ │ ├── RequestInvocation.java │ │ ├── ResponseDecoder.java │ │ ├── ResponseEncoder.java │ │ └── ResponseInvocation.java │ └── resources │ └── META-INF │ └── services │ ├── com.github.liyue2008.rpc.NameService │ ├── com.github.liyue2008.rpc.RpcAccessPoint │ ├── com.github.liyue2008.rpc.client.StubFactory │ ├── com.github.liyue2008.rpc.serialize.Serializer │ ├── com.github.liyue2008.rpc.server.ServiceProviderRegistry │ ├── com.github.liyue2008.rpc.transport.RequestHandler │ ├── com.github.liyue2008.rpc.transport.TransportClient │ └── com.github.liyue2008.rpc.transport.TransportServer └── server ├── pom.xml └── src └── main └── java └── com └── github └── liyue2008 └── rpc └── server ├── HelloServiceImpl.java └── Server.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | target/ 4 | -------------------------------------------------------------------------------- /HEADER: -------------------------------------------------------------------------------- 1 | Licensed under the Apache License, Version 2.0 (the "License"); 2 | you may not use this file except in compliance with the License. 3 | You may obtain a copy of the License at 4 | 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 环境要求 2 | 3 | 运行示例之前需要先安装: 4 | 5 | * JDK 1.8 6 | * Maven 3.3.9 7 | 8 | ```bash 9 | $java -version 10 | java version "1.8.0_202" 11 | Java(TM) SE Runtime Environment (build 1.8.0_202-b08) 12 | Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode) 13 | 14 | $mvn -version 15 | Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00) 16 | ``` 17 | 18 | ## 下载编译源代码 19 | 20 | ```bash 21 | $git clone git@github.com:liyue2008/simple-rpc-framework.git 22 | $cd simple-rpc-framework 23 | $mvn package 24 | ``` 25 | 26 | ## 启动服务端 27 | 28 | ```bash 29 | $java -jar server/target/server-1.0-SNAPSHOT-jar-with-dependencies.jar 30 | [main] INFO com.github.liyue2008.rpc.server.Server - 创建并启动RpcAccessPoint... 31 | [main] INFO com.github.liyue2008.rpc.transport.RequestHandlerRegistry - Load request handler, type: 0, class: com.github.liyue2008.rpc.transport.RpcRequestHandler. 32 | [main] INFO com.github.liyue2008.rpc.server.Server - 向RpcAccessPoint注册com.github.liyue2008.rpc.hello.HelloService服务... 33 | [main] INFO com.github.liyue2008.rpc.server.Server - 服务名: com.github.liyue2008.rpc.hello.HelloService, 向NameService注册... 34 | [main] INFO com.github.liyue2008.rpc.nameservice.LocalFileNameService - Register service: com.github.liyue2008.rpc.hello.HelloService, uri: rpc://localhost:9999. 35 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: com.github.liyue2008.rpc.nameservice.Metadata, type: 100. 36 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: java.lang.String, type: 0. 37 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: com.github.liyue2008.rpc.client.stubs.RpcRequest, type: 101. 38 | [main] INFO com.github.liyue2008.rpc.nameservice.LocalFileNameService - Metadata: 39 | Classname: com.github.liyue2008.rpc.hello.HelloService 40 | URIs: 41 | rpc://localhost:9999 42 | 43 | [main] INFO com.github.liyue2008.rpc.server.Server - 开始提供服务,按任何键退出. 44 | ``` 45 | 46 | ## 运行客户端 47 | 48 | ```bash 49 | java -jar client/target/client-1.0-SNAPSHOT-jar-with-dependencies.jar 50 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: com.github.liyue2008.rpc.nameservice.Metadata, type: 100. 51 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: java.lang.String, type: 0. 52 | [main] INFO com.github.liyue2008.rpc.serialize.SerializeSupport - Found serializer, class: com.github.liyue2008.rpc.client.stubs.RpcRequest, type: 101. 53 | [main] INFO com.github.liyue2008.rpc.nameservice.LocalFileNameService - Metadata: 54 | Classname: com.github.liyue2008.rpc.hello.HelloService 55 | URIs: 56 | rpc://localhost:9999 57 | 58 | [main] INFO com.github.liyue2008.rpc.client.Client - 找到服务com.github.liyue2008.rpc.hello.HelloService,提供者: rpc://localhost:9999. 59 | [main] INFO com.github.liyue2008.rpc.client.Client - 请求服务, name: Master MQ... 60 | [main] INFO com.github.liyue2008.rpc.client.Client - 收到响应: Hello, Master MQ. 61 | ``` 62 | 63 | ## RPC框架功能定义 64 | 65 | RPC框架对外提供的所有服务定义在一个接口RpcAccessPoint中: 66 | 67 | ```java 68 | /** 69 | * RPC框架对外提供的服务接口 70 | */ 71 | public interface RpcAccessPoint extends Closeable{ 72 | /** 73 | * 客户端获取远程服务的引用 74 | * @param uri 远程服务地址 75 | * @param serviceClass 服务的接口类的Class 76 | * @param 服务接口的类型 77 | * @return 远程服务引用 78 | */ 79 | T getRemoteService(URI uri, Class serviceClass); 80 | 81 | /** 82 | * 服务端注册服务的实现实例 83 | * @param service 实现实例 84 | * @param serviceClass 服务的接口类的Class 85 | * @param 服务接口的类型 86 | * @return 服务地址 87 | */ 88 | URI addServiceProvider(T service, Class serviceClass); 89 | 90 | /** 91 | * 服务端启动RPC框架,监听接口,开始提供远程服务。 92 | * @return 服务实例,用于程序停止的时候安全关闭服务。 93 | */ 94 | Closeable startServer() throws Exception; 95 | } 96 | ``` 97 | 98 | 注册中心的接口NameService: 99 | 100 | ```java 101 | /** 102 | * 注册中心 103 | */ 104 | public interface NameService { 105 | /** 106 | * 注册服务 107 | * @param serviceName 服务名称 108 | * @param uri 服务地址 109 | */ 110 | void registerService(String serviceName, URI uri) throws IOException; 111 | 112 | /** 113 | * 查询服务地址 114 | * @param serviceName 服务名称 115 | * @return 服务地址 116 | */ 117 | URI lookupService(String serviceName) throws IOException; 118 | } 119 | 120 | ``` 121 | 122 | ## 例子 123 | 124 | 需要先定义一个服务接口: 125 | 126 | ```java 127 | public interface HelloService { 128 | String hello(String name); 129 | } 130 | ``` 131 | 132 | 客户端: 133 | 134 | ```java 135 | URI uri = nameService.lookupService(serviceName); 136 | HelloService helloService = rpcAccessPoint.getRemoteService(uri, HelloService.class); 137 | String response = helloService.hello(name); 138 | logger.info("收到响应: {}.", response); 139 | ``` 140 | 141 | 服务端: 142 | 143 | 定义一个HelloService的实现: 144 | 145 | ```java 146 | public class HelloServiceImpl implements HelloService { 147 | @Override 148 | public String hello(String name) { 149 | String ret = "Hello, " + name; 150 | return ret; 151 | } 152 | } 153 | ``` 154 | 155 | 然后,把实现注册到RPC框架上,并启动RPC服务: 156 | 157 | ```java 158 | rpcAccessPoint.startServer(); 159 | URI uri = rpcAccessPoint.addServiceProvider(helloService, HelloService.class); 160 | nameService.registerService(serviceName, uri); 161 | ``` 162 | 163 | ## 项目结构 164 | 165 | Module | 说明 166 | -- | -- 167 | client | 例子:客户端 168 | server | 例子:服务端 169 | rpc-api | RPC框架接口 170 | hello-service-api | 例子:接口定义 171 | rpc-netty | 基于Netty实现的RPC框架 172 | -------------------------------------------------------------------------------- /client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | simple-rpc-framework 22 | com.github.liyue2008 23 | 1.0-SNAPSHOT 24 | 25 | 4.0.0 26 | 27 | client 28 | 29 | 30 | 31 | com.github.liyue2008 32 | hello-service-api 33 | ${project.version} 34 | 35 | 36 | com.github.liyue2008 37 | rpc-api 38 | ${project.version} 39 | 40 | 41 | org.slf4j 42 | slf4j-api 43 | 44 | 45 | org.slf4j 46 | slf4j-simple 47 | runtime 48 | 49 | 50 | com.github.liyue2008 51 | rpc-netty 52 | ${project.version} 53 | runtime 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-dependency-plugin 61 | 62 | 63 | copy-dependencies 64 | prepare-package 65 | 66 | copy-dependencies 67 | 68 | 69 | 70 | ${project.build.directory}/libs 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-assembly-plugin 79 | 80 | 81 | package 82 | 83 | single 84 | 85 | 86 | 87 | 88 | 89 | com.github.liyue2008.rpc.client.Client 90 | 91 | 92 | 93 | 94 | jar-with-dependencies 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /client/src/main/java/com/github/liyue2008/rpc/client/Client.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import com.github.liyue2008.rpc.NameService; 17 | import com.github.liyue2008.rpc.RpcAccessPoint; 18 | import com.github.liyue2008.rpc.hello.HelloService; 19 | import com.github.liyue2008.rpc.hello.entity.HelloRequest; 20 | import com.github.liyue2008.rpc.hello.entity.HelloResult; 21 | import com.github.liyue2008.rpc.spi.ServiceSupport; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | import java.io.File; 26 | import java.io.IOException; 27 | import java.net.URI; 28 | import java.util.Arrays; 29 | import java.util.Date; 30 | 31 | /** 32 | * @author LiYue 33 | * Date: 2019/9/20 34 | */ 35 | public class Client { 36 | private static final Logger logger = LoggerFactory.getLogger(Client.class); 37 | public static void main(String [] args) throws IOException { 38 | String serviceName = HelloService.class.getCanonicalName(); 39 | File tmpDirFile = new File(System.getProperty("java.io.tmpdir")); 40 | File file = new File(tmpDirFile, "simple_rpc_name_service.data"); 41 | String name = "Master MQ"; 42 | try(RpcAccessPoint rpcAccessPoint = ServiceSupport.load(RpcAccessPoint.class)) { 43 | NameService nameService = rpcAccessPoint.getNameService(file.toURI()); 44 | assert nameService != null; 45 | URI uri = nameService.lookupService(serviceName); 46 | assert uri != null; 47 | logger.info("找到服务{},提供者: {}.", serviceName, uri); 48 | HelloService helloService = rpcAccessPoint.getRemoteService(uri, HelloService.class); 49 | logger.info("请求服务, name: {}...", name); 50 | HelloRequest request = new HelloRequest(); 51 | request.setParam(Arrays.asList("hello","world")); 52 | request.setTimestamp(new Date().toString()); 53 | HelloResult response = helloService.helloMoreResult(request); 54 | logger.info("收到响应: {}.", response.toString()); 55 | } 56 | 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /client/src/test/RealSubject.java: -------------------------------------------------------------------------------- 1 | public class RealSubject implements Subject { 2 | 3 | @Override 4 | public void doSomething() { 5 | System.out.println("RealSubject do something"); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /hello-service-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | simple-rpc-framework 22 | com.github.liyue2008 23 | 1.0-SNAPSHOT 24 | 25 | 4.0.0 26 | 27 | hello-service-api 28 | 29 | 30 | -------------------------------------------------------------------------------- /hello-service-api/src/main/java/com/github/liyue2008/rpc/hello/HelloService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.hello; 15 | 16 | import com.github.liyue2008.rpc.hello.entity.HelloRequest; 17 | import com.github.liyue2008.rpc.hello.entity.HelloResult; 18 | 19 | /** 20 | * @author LiYue 21 | * Date: 2019/9/20 22 | */ 23 | public interface HelloService { 24 | 25 | String hello(String name); 26 | 27 | HelloResult helloMoreResult(String name,String value); 28 | 29 | HelloResult helloMoreResult(HelloRequest request); 30 | } 31 | -------------------------------------------------------------------------------- /hello-service-api/src/main/java/com/github/liyue2008/rpc/hello/entity/HelloRequest.java: -------------------------------------------------------------------------------- 1 | package com.github.liyue2008.rpc.hello.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | public class HelloRequest implements Serializable { 6 | 7 | private Object param; 8 | private String timestamp; 9 | 10 | public Object getParam() { 11 | return param; 12 | } 13 | 14 | public void setParam(Object param) { 15 | this.param = param; 16 | } 17 | 18 | public String getTimestamp() { 19 | return timestamp; 20 | } 21 | 22 | public void setTimestamp(String timestamp) { 23 | this.timestamp = timestamp; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return "HelloRequest{" + 29 | "param=" + param + 30 | ", timestamp='" + timestamp + '\'' + 31 | '}'; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /hello-service-api/src/main/java/com/github/liyue2008/rpc/hello/entity/HelloResult.java: -------------------------------------------------------------------------------- 1 | package com.github.liyue2008.rpc.hello.entity; 2 | 3 | import java.io.Serializable; 4 | 5 | public class HelloResult implements Serializable { 6 | 7 | private String resultCode; 8 | private boolean isSuccess; 9 | private Object result; 10 | 11 | public String getResultCode() { 12 | return resultCode; 13 | } 14 | 15 | public void setResultCode(String resultCode) { 16 | this.resultCode = resultCode; 17 | } 18 | 19 | public boolean isSuccess() { 20 | return isSuccess; 21 | } 22 | 23 | public void setSuccess(boolean success) { 24 | isSuccess = success; 25 | } 26 | 27 | public Object getResult() { 28 | return result; 29 | } 30 | 31 | public void setResult(Object result) { 32 | this.result = result; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | return "HelloResult{" + 38 | "resultCode='" + resultCode + '\'' + 39 | ", isSuccess=" + isSuccess + 40 | ", result=" + result + 41 | '}'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 4.0.0 21 | 22 | com.github.liyue2008 23 | simple-rpc-framework 24 | 1.0-SNAPSHOT 25 | 26 | client 27 | server 28 | rpc-api 29 | hello-service-api 30 | rpc-netty 31 | 32 | pom 33 | Simple RPC Framework 34 | A simple RPC framework example. 35 | 36 | 37 | maven-ali 38 | http://maven.aliyun.com/nexus/content/groups/public/ 39 | 40 | true 41 | 42 | 43 | true 44 | always 45 | fail 46 | 47 | 48 | 49 | 50 | 51 | UTF-8 52 | UTF-8 53 | 54 | 1.8 55 | 1.8 56 | 3.8.0 57 | 3.1.0 58 | 3.1.1 59 | 3.1.0 60 | 3.0.1 61 | 2.22.0 62 | -parameters 63 | 3.1.0 64 | 65 | 66 | 2.9.0 67 | 1.7.25 68 | 2.6 69 | 2.8.5 70 | 1.0 71 | 4.1.42.Final 72 | 3.3.0 73 | 74 | 75 | 76 | 77 | 78 | org.slf4j 79 | slf4j-api 80 | ${slf4j.version} 81 | 82 | 83 | 84 | org.slf4j 85 | slf4j-simple 86 | ${slf4j.version} 87 | 88 | 89 | com.google.code.gson 90 | gson 91 | ${gson.version} 92 | 93 | 94 | commons-io 95 | commons-io 96 | ${commons.io.version} 97 | 98 | 99 | com.itranswarp 100 | compiler 101 | ${com.itranswarp.compiler.version} 102 | 103 | 104 | io.netty 105 | netty-all 106 | ${netty.version} 107 | 108 | 109 | 110 | cglib 111 | cglib 112 | ${cglib.version} 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-compiler-plugin 123 | ${maven-compiler-plugin.version} 124 | 125 | 126 | -XDignore.symbol.file 127 | 128 | true 129 | 130 | 131 | 132 | 133 | org.apache.maven.plugins 134 | maven-resources-plugin 135 | ${maven-resources-plugin.version} 136 | 137 | 138 | org.apache.maven.plugins 139 | maven-dependency-plugin 140 | ${maven-dependency-plugin.version} 141 | 142 | 143 | org.apache.maven.plugins 144 | maven-surefire-plugin 145 | ${maven-surefire-plugin.version} 146 | 147 | 148 | org.apache.maven.plugins 149 | maven-assembly-plugin 150 | ${maven-assembly-plugin.version} 151 | 152 | 153 | pl.project13.maven 154 | git-commit-id-plugin 155 | ${git-commit-id-pulgin.version} 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | license 165 | 166 | 167 | 168 | com.mycila 169 | license-maven-plugin 170 | 3.0 171 | 172 | 173 |
${maven.multiModuleProjectDirectory}/HEADER
174 |
175 | 176 | 177 | 178 | format 179 | 180 | 181 | 182 |
183 |
184 | 185 |
186 |
187 |
188 |
-------------------------------------------------------------------------------- /rpc-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | simple-rpc-framework 22 | com.github.liyue2008 23 | 1.0-SNAPSHOT 24 | 25 | 4.0.0 26 | 27 | rpc-api 28 | 29 | 30 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/github/liyue2008/rpc/NameService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc; 15 | 16 | import java.io.IOException; 17 | import java.net.URI; 18 | import java.util.Collection; 19 | 20 | /** 21 | * 注册中心 22 | * @author LiYue 23 | * Date: 2019/9/20 24 | */ 25 | public interface NameService { 26 | 27 | /** 28 | * 所有支持的协议 29 | */ 30 | Collection supportedSchemes(); 31 | 32 | /** 33 | * 连接注册中心 34 | * @param nameServiceUri 注册中心地址 35 | */ 36 | void connect(URI nameServiceUri); 37 | /** 38 | * 注册服务 39 | * @param serviceName 服务名称 40 | * @param uri 服务地址 41 | */ 42 | void registerService(String serviceName, URI uri) throws IOException; 43 | 44 | /** 45 | * 查询服务地址 46 | * @param serviceName 服务名称 47 | * @return 服务地址 48 | */ 49 | URI lookupService(String serviceName) throws IOException; 50 | } 51 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/github/liyue2008/rpc/RpcAccessPoint.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc; 15 | 16 | import com.github.liyue2008.rpc.spi.ServiceSupport; 17 | 18 | import java.io.Closeable; 19 | import java.net.URI; 20 | import java.util.Collection; 21 | 22 | /** 23 | * RPC框架对外提供的服务接口 24 | * @author LiYue 25 | * Date: 2019/9/20 26 | */ 27 | public interface RpcAccessPoint extends Closeable{ 28 | /** 29 | * 客户端获取远程服务的引用 30 | * @param uri 远程服务地址 31 | * @param serviceClass 服务的接口类的Class 32 | * @param 服务接口的类型 33 | * @return 远程服务引用 34 | */ 35 | T getRemoteService(URI uri, Class serviceClass); 36 | 37 | /** 38 | * 服务端注册服务的实现实例 39 | * @param service 实现实例 40 | * @param serviceClass 服务的接口类的Class 41 | * @param 服务接口的类型 42 | * @return 服务地址 43 | */ 44 | URI addServiceProvider(T service, Class serviceClass); 45 | 46 | /** 47 | * 获取注册中心的引用 48 | * @param nameServiceUri 注册中心URI 49 | * @return 注册中心引用 50 | */ 51 | default NameService getNameService(URI nameServiceUri) { 52 | Collection nameServices = ServiceSupport.loadAll(NameService.class); 53 | for (NameService nameService : nameServices) { 54 | if(nameService.supportedSchemes().contains(nameServiceUri.getScheme())) { 55 | nameService.connect(nameServiceUri); 56 | return nameService; 57 | } 58 | } 59 | return null; 60 | } 61 | 62 | /** 63 | * 服务端启动RPC框架,监听接口,开始提供远程服务。 64 | * @return 服务实例,用于程序停止的时候安全关闭服务。 65 | */ 66 | Closeable startServer() throws Exception; 67 | } 68 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/github/liyue2008/rpc/spi/ServiceLoadException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.spi; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019-03-20 19 | */ 20 | public class ServiceLoadException extends RuntimeException { 21 | } 22 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/github/liyue2008/rpc/spi/ServiceSupport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.spi; 15 | 16 | import java.util.Collection; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.ServiceLoader; 20 | import java.util.stream.Collectors; 21 | import java.util.stream.StreamSupport; 22 | 23 | /** 24 | * SPI类加载器帮助类 25 | * @author LiYue 26 | * Date: 2019-03-26 27 | */ 28 | public class ServiceSupport { 29 | private final static Map singletonServices = new HashMap<>(); 30 | public synchronized static S load(Class service) { 31 | return StreamSupport. 32 | stream(ServiceLoader.load(service).spliterator(), false) 33 | .map(ServiceSupport::singletonFilter) 34 | .findFirst().orElseThrow(ServiceLoadException::new); 35 | } 36 | public synchronized static Collection loadAll(Class service) { 37 | return StreamSupport. 38 | stream(ServiceLoader.load(service).spliterator(), false) 39 | .map(ServiceSupport::singletonFilter).collect(Collectors.toList()); 40 | } 41 | 42 | @SuppressWarnings("unchecked") 43 | private static S singletonFilter(S service) { 44 | 45 | if(service.getClass().isAnnotationPresent(Singleton.class)) { 46 | String className = service.getClass().getCanonicalName(); 47 | Object singletonInstance = singletonServices.putIfAbsent(className, service); 48 | return singletonInstance == null ? service : (S) singletonInstance; 49 | } else { 50 | return service; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rpc-api/src/main/java/com/github/liyue2008/rpc/spi/Singleton.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.spi; 15 | 16 | import java.lang.annotation.ElementType; 17 | import java.lang.annotation.Retention; 18 | import java.lang.annotation.RetentionPolicy; 19 | import java.lang.annotation.Target; 20 | 21 | /** 22 | * @author LiYue 23 | * Date: 2019/9/30 24 | */ 25 | @Target(ElementType.TYPE) 26 | @Retention(RetentionPolicy.RUNTIME) 27 | public @interface Singleton { 28 | } 29 | -------------------------------------------------------------------------------- /rpc-netty/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | simple-rpc-framework 22 | com.github.liyue2008 23 | 1.0-SNAPSHOT 24 | 25 | 4.0.0 26 | 27 | rpc-netty 28 | 29 | 30 | 31 | com.github.liyue2008 32 | rpc-api 33 | ${project.version} 34 | 35 | 36 | org.slf4j 37 | slf4j-api 38 | 39 | 40 | io.netty 41 | netty-all 42 | 43 | 44 | com.itranswarp 45 | compiler 46 | 47 | 48 | cglib 49 | cglib 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/NettyRpcAccessPoint.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc; 15 | 16 | import com.github.liyue2008.rpc.client.StubFactory; 17 | import com.github.liyue2008.rpc.server.RpcRequestHandler; 18 | import com.github.liyue2008.rpc.server.ServiceProviderRegistry; 19 | import com.github.liyue2008.rpc.spi.ServiceSupport; 20 | import com.github.liyue2008.rpc.transport.RequestHandlerRegistry; 21 | import com.github.liyue2008.rpc.transport.Transport; 22 | import com.github.liyue2008.rpc.transport.TransportClient; 23 | import com.github.liyue2008.rpc.transport.TransportServer; 24 | 25 | import java.io.Closeable; 26 | import java.net.InetSocketAddress; 27 | import java.net.URI; 28 | import java.util.Collection; 29 | import java.util.Map; 30 | import java.util.concurrent.ConcurrentHashMap; 31 | import java.util.concurrent.TimeoutException; 32 | 33 | /** 34 | * @author LiYue 35 | * Date: 2019/9/20 36 | */ 37 | public class NettyRpcAccessPoint implements RpcAccessPoint { 38 | private final String host = "localhost"; 39 | private final int port = 9999; 40 | private final URI uri = URI.create("rpc://" + host + ":" + port); 41 | private TransportServer server = null; 42 | private TransportClient client = ServiceSupport.load(TransportClient.class); 43 | private final Map clientMap = new ConcurrentHashMap<>(); 44 | private final StubFactory stubFactory = ServiceSupport.load(StubFactory.class); 45 | private final ServiceProviderRegistry serviceProviderRegistry = ServiceSupport.load(ServiceProviderRegistry.class); 46 | 47 | @Override 48 | public T getRemoteService(URI uri, Class serviceClass) { 49 | Transport transport = clientMap.computeIfAbsent(uri, this::createTransport); 50 | return stubFactory.createStub(transport, serviceClass); 51 | } 52 | 53 | private Transport createTransport(URI uri) { 54 | try { 55 | return client.createTransport(new InetSocketAddress(uri.getHost(), uri.getPort()),30000L); 56 | } catch (InterruptedException | TimeoutException e) { 57 | throw new RuntimeException(e); 58 | } 59 | } 60 | @Override 61 | public synchronized URI addServiceProvider(T service, Class serviceClass) { 62 | serviceProviderRegistry.addServiceProvider(serviceClass, service); 63 | return uri; 64 | } 65 | 66 | @Override 67 | public synchronized Closeable startServer() throws Exception { 68 | if (null == server) { 69 | server = ServiceSupport.load(TransportServer.class); 70 | server.start(RequestHandlerRegistry.getInstance(), port); 71 | 72 | } 73 | return () -> { 74 | if(null != server) { 75 | server.stop(); 76 | } 77 | }; 78 | } 79 | 80 | @Override 81 | public void close() { 82 | if(null != server) { 83 | server.stop(); 84 | } 85 | client.close(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/CGLibDynamicProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.liyue2008.rpc.client; 2 | 3 | import com.github.liyue2008.rpc.client.stubs.AbstractStub; 4 | import com.github.liyue2008.rpc.client.stubs.RpcRequest; 5 | import com.github.liyue2008.rpc.serialize.SerializeSupport; 6 | import net.sf.cglib.proxy.Enhancer; 7 | import net.sf.cglib.proxy.MethodInterceptor; 8 | import net.sf.cglib.proxy.MethodProxy; 9 | 10 | import java.lang.reflect.Method; 11 | 12 | public class CGLibDynamicProxy extends AbstractStub implements MethodInterceptor { 13 | 14 | private Class clz; 15 | 16 | public CGLibDynamicProxy(Class clz){ 17 | this.clz = clz; 18 | } 19 | 20 | private Enhancer enhancer = new Enhancer(); 21 | 22 | public Object getProxy(){ 23 | //设置需要创建子类的类 24 | enhancer.setSuperclass(clz); 25 | enhancer.setCallback(this); 26 | //通过字节码技术动态创建子类实例 27 | return enhancer.create(); 28 | } 29 | 30 | @Override 31 | public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 32 | return SerializeSupport.parse(invokeRemote(new RpcRequest(clz.getCanonicalName(),method.getName(),SerializeSupport.serialize(objects)))); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/CGLibDynamicStubFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import com.github.liyue2008.rpc.transport.Transport; 17 | import com.itranswarp.compiler.JavaStringCompiler; 18 | 19 | import java.util.Map; 20 | 21 | /** 22 | * @author LiYue 23 | * Date: 2019/9/27 24 | */ 25 | public class CGLibDynamicStubFactory implements StubFactory{ 26 | 27 | @Override 28 | @SuppressWarnings("unchecked") 29 | public T createStub(Transport transport, Class serviceClass) { 30 | try { 31 | // jdk动态代理测试 32 | CGLibDynamicProxy proxy = new CGLibDynamicProxy(serviceClass); 33 | proxy.setTransport(transport); 34 | // 返回这个桩 35 | return (T) proxy.getProxy(); 36 | } catch (Throwable t) { 37 | throw new RuntimeException(t); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/DynamicStubFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import com.github.liyue2008.rpc.transport.Transport; 17 | import com.itranswarp.compiler.JavaStringCompiler; 18 | 19 | 20 | import java.util.Map; 21 | 22 | /** 23 | * @author LiYue 24 | * Date: 2019/9/27 25 | */ 26 | public class DynamicStubFactory implements StubFactory{ 27 | private final static String STUB_SOURCE_TEMPLATE = 28 | "package com.github.liyue2008.rpc.client.stubs;\n" + 29 | "import com.github.liyue2008.rpc.serialize.SerializeSupport;\n" + 30 | "\n" + 31 | "public class %s extends AbstractStub implements %s {\n" + 32 | " @Override\n" + 33 | " public String %s(String arg) {\n" + 34 | " return SerializeSupport.parse(\n" + 35 | " invokeRemote(\n" + 36 | " new RpcRequest(\n" + 37 | " \"%s\",\n" + 38 | " \"%s\",\n" + 39 | " SerializeSupport.serialize(arg)\n" + 40 | " )\n" + 41 | " )\n" + 42 | " );\n" + 43 | " }\n" + 44 | "}"; 45 | 46 | @Override 47 | @SuppressWarnings("unchecked") 48 | public T createStub(Transport transport, Class serviceClass) { 49 | try { 50 | // 填充模板 51 | String stubSimpleName = serviceClass.getSimpleName() + "Stub"; 52 | String classFullName = serviceClass.getName(); 53 | String stubFullName = "com.github.liyue2008.rpc.client.stubs." + stubSimpleName; 54 | String methodName = serviceClass.getMethods()[0].getName(); 55 | 56 | String source = String.format(STUB_SOURCE_TEMPLATE, stubSimpleName, classFullName, methodName, classFullName, methodName); 57 | // 编译源代码 58 | JavaStringCompiler compiler = new JavaStringCompiler(); 59 | Map results = compiler.compile(stubSimpleName + ".java", source); 60 | // 加载编译好的类 61 | Class clazz = compiler.loadClass(stubFullName, results); 62 | 63 | // 把Transport赋值给桩 64 | ServiceStub stubInstance = (ServiceStub) clazz.newInstance(); 65 | stubInstance.setTransport(transport); 66 | // 返回这个桩 67 | return (T) stubInstance; 68 | } catch (Throwable t) { 69 | throw new RuntimeException(t); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/RequestIdSupport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | 18 | /** 19 | * @author LiYue 20 | * Date: 2019/9/23 21 | */ 22 | public class RequestIdSupport { 23 | private final static AtomicInteger nextRequestId = new AtomicInteger(0); 24 | public static int next() { 25 | return nextRequestId.getAndIncrement(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/ServiceStub.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import com.github.liyue2008.rpc.transport.Transport; 17 | 18 | /** 19 | * @author LiYue 20 | * Date: 2019/9/27 21 | */ 22 | public interface ServiceStub { 23 | void setTransport(Transport transport); 24 | } 25 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/ServiceTypes.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/23 19 | */ 20 | public class ServiceTypes { 21 | public final static int TYPE_RPC_REQUEST = 0; 22 | } 23 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/StubFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client; 15 | 16 | import com.github.liyue2008.rpc.transport.Transport; 17 | 18 | /** 19 | * @author LiYue 20 | * Date: 2019/9/27 21 | */ 22 | public interface StubFactory { 23 | T createStub(Transport transport, Class serviceClass); 24 | } 25 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/stubs/AbstractStub.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client.stubs; 15 | 16 | import com.github.liyue2008.rpc.client.RequestIdSupport; 17 | import com.github.liyue2008.rpc.client.ServiceStub; 18 | import com.github.liyue2008.rpc.client.ServiceTypes; 19 | import com.github.liyue2008.rpc.serialize.SerializeSupport; 20 | import com.github.liyue2008.rpc.transport.Transport; 21 | import com.github.liyue2008.rpc.transport.command.Code; 22 | import com.github.liyue2008.rpc.transport.command.Command; 23 | import com.github.liyue2008.rpc.transport.command.Header; 24 | import com.github.liyue2008.rpc.transport.command.ResponseHeader; 25 | 26 | import java.util.concurrent.ExecutionException; 27 | 28 | /** 29 | * @author LiYue 30 | * Date: 2019/9/27 31 | */ 32 | public abstract class AbstractStub implements ServiceStub { 33 | protected Transport transport; 34 | 35 | protected byte [] invokeRemote(RpcRequest request) { 36 | Header header = new Header(ServiceTypes.TYPE_RPC_REQUEST, 1, RequestIdSupport.next()); 37 | byte [] payload = SerializeSupport.serialize(request); 38 | Command requestCommand = new Command(header, payload); 39 | try { 40 | Command responseCommand = transport.send(requestCommand).get(); 41 | ResponseHeader responseHeader = (ResponseHeader) responseCommand.getHeader(); 42 | if(responseHeader.getCode() == Code.SUCCESS.getCode()) { 43 | return responseCommand.getPayload(); 44 | } else { 45 | throw new Exception(responseHeader.getError()); 46 | } 47 | 48 | } catch (ExecutionException e) { 49 | throw new RuntimeException(e.getCause()); 50 | } catch (Throwable e) { 51 | throw new RuntimeException(e); 52 | } 53 | } 54 | 55 | @Override 56 | public void setTransport(Transport transport) { 57 | this.transport = transport; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/client/stubs/RpcRequest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.client.stubs; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/27 19 | */ 20 | public class RpcRequest { 21 | private final String interfaceName; 22 | private final String methodName; 23 | private final byte [] serializedArguments; 24 | 25 | public RpcRequest(String interfaceName, String methodName, byte[] serializedArguments) { 26 | this.interfaceName = interfaceName; 27 | this.methodName = methodName; 28 | this.serializedArguments = serializedArguments; 29 | } 30 | 31 | public String getInterfaceName() { 32 | return interfaceName; 33 | } 34 | 35 | public String getMethodName() { 36 | return methodName; 37 | } 38 | 39 | public byte[] getSerializedArguments() { 40 | return serializedArguments; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/nameservice/LocalFileNameService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.nameservice; 15 | 16 | import com.github.liyue2008.rpc.NameService; 17 | import com.github.liyue2008.rpc.serialize.SerializeSupport; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.io.RandomAccessFile; 24 | import java.net.URI; 25 | import java.nio.ByteBuffer; 26 | import java.nio.channels.FileChannel; 27 | import java.nio.channels.FileLock; 28 | import java.util.ArrayList; 29 | import java.util.Collection; 30 | import java.util.Collections; 31 | import java.util.List; 32 | import java.util.concurrent.ThreadLocalRandom; 33 | 34 | /** 35 | * @author LiYue 36 | * Date: 2019/9/20 37 | */ 38 | public class LocalFileNameService implements NameService { 39 | private static final Logger logger = LoggerFactory.getLogger(LocalFileNameService.class); 40 | private static final Collection schemes = Collections.singleton("file"); 41 | private File file; 42 | 43 | @Override 44 | public Collection supportedSchemes() { 45 | return schemes; 46 | } 47 | 48 | @Override 49 | public void connect(URI nameServiceUri) { 50 | if(schemes.contains(nameServiceUri.getScheme())) { 51 | file = new File(nameServiceUri); 52 | } else { 53 | throw new RuntimeException("Unsupported scheme!"); 54 | } 55 | } 56 | 57 | @Override 58 | public synchronized void registerService(String serviceName, URI uri) throws IOException { 59 | logger.info("Register service: {}, uri: {}.", serviceName, uri); 60 | try(RandomAccessFile raf = new RandomAccessFile(file, "rw"); 61 | FileChannel fileChannel = raf.getChannel()) { 62 | FileLock lock = fileChannel.lock(); 63 | try { 64 | int fileLength = (int) raf.length(); 65 | Metadata metadata; 66 | byte[] bytes; 67 | if(fileLength > 0) { 68 | bytes = new byte[(int) raf.length()]; 69 | ByteBuffer buffer = ByteBuffer.wrap(bytes); 70 | while (buffer.hasRemaining()) { 71 | fileChannel.read(buffer); 72 | } 73 | 74 | metadata = SerializeSupport.parse(bytes); 75 | } else { 76 | metadata = new Metadata(); 77 | } 78 | List uris = metadata.computeIfAbsent(serviceName, k -> new ArrayList<>()); 79 | if(!uris.contains(uri)) { 80 | uris.add(uri); 81 | } 82 | logger.info(metadata.toString()); 83 | 84 | bytes = SerializeSupport.serialize(metadata); 85 | fileChannel.truncate(bytes.length); 86 | fileChannel.position(0L); 87 | fileChannel.write(ByteBuffer.wrap(bytes)); 88 | fileChannel.force(true); 89 | } finally { 90 | lock.release(); 91 | } 92 | } 93 | } 94 | 95 | @Override 96 | public URI lookupService(String serviceName) throws IOException { 97 | Metadata metadata; 98 | try(RandomAccessFile raf = new RandomAccessFile(file, "rw"); 99 | FileChannel fileChannel = raf.getChannel()) { 100 | FileLock lock = fileChannel.lock(); 101 | try { 102 | byte [] bytes = new byte[(int) raf.length()]; 103 | ByteBuffer buffer = ByteBuffer.wrap(bytes); 104 | while (buffer.hasRemaining()) { 105 | fileChannel.read(buffer); 106 | } 107 | metadata = bytes.length == 0? new Metadata(): SerializeSupport.parse(bytes); 108 | logger.info(metadata.toString()); 109 | } finally { 110 | lock.release(); 111 | } 112 | } 113 | 114 | List uris = metadata.get(serviceName); 115 | if(null == uris || uris.isEmpty()) { 116 | return null; 117 | } else { 118 | return uris.get(ThreadLocalRandom.current().nextInt(uris.size())); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/nameservice/Metadata.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.nameservice; 15 | 16 | import java.net.URI; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | 20 | /** 21 | * 22 | * @author LiYue 23 | * Date: 2019/9/20 24 | */ 25 | public class Metadata extends HashMap/*服务提供者URI列表*/> { 26 | 27 | @Override 28 | public String toString() { 29 | StringBuilder sb = new StringBuilder("Metadata:").append("\n"); 30 | for (Entry> entry : entrySet()) { 31 | sb.append("\t").append("Classname: ") 32 | .append(entry.getKey()).append("\n"); 33 | sb.append("\t").append("URIs:").append("\n"); 34 | for (URI uri : entry.getValue()) { 35 | sb.append("\t\t").append(uri).append("\n"); 36 | } 37 | } 38 | return sb.toString(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/SerializeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019-08-12 19 | */ 20 | public class SerializeException extends RuntimeException { 21 | public SerializeException(String msg) { 22 | super(msg); 23 | } 24 | public SerializeException(Throwable throwable){ super(throwable);} 25 | } 26 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/SerializeSupport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize; 15 | 16 | import com.github.liyue2008.rpc.spi.ServiceSupport; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | /** 24 | * @author LiYue 25 | * Date: 2019/9/20 26 | */ 27 | @SuppressWarnings("unchecked") 28 | public class SerializeSupport { 29 | private static final Logger logger = LoggerFactory.getLogger(SerializeSupport.class); 30 | private static Map/*序列化对象类型*/, Serializer/*序列化实现*/> serializerMap = new HashMap<>(); 31 | private static Map/*序列化对象类型*/> typeMap = new HashMap<>(); 32 | 33 | static { 34 | for (Serializer serializer : ServiceSupport.loadAll(Serializer.class)) { 35 | registerType(serializer.type(), serializer.getSerializeClass(), serializer); 36 | logger.info("Found serializer, class: {}, type: {}.", 37 | serializer.getSerializeClass().getCanonicalName(), 38 | serializer.type()); 39 | } 40 | } 41 | private static byte parseEntryType(byte[] buffer) { 42 | return buffer[0]; 43 | } 44 | private static void registerType(byte type, Class eClass, Serializer serializer) { 45 | serializerMap.put(eClass, serializer); 46 | typeMap.put(type, eClass); 47 | } 48 | @SuppressWarnings("unchecked") 49 | private static E parse(byte [] buffer, int offset, int length, Class eClass) { 50 | Object entry = serializerMap.getOrDefault(eClass,serializerMap.get(Object.class)).parse(buffer, offset, length); 51 | if (eClass.isAssignableFrom(entry.getClass())) { 52 | return (E) entry; 53 | } else { 54 | throw new SerializeException("Type mismatch!"); 55 | } 56 | } 57 | public static E parse(byte [] buffer) { 58 | return parse(buffer, 0, buffer.length); 59 | } 60 | 61 | private static E parse(byte[] buffer, int offset, int length) { 62 | byte type = parseEntryType(buffer); 63 | @SuppressWarnings("unchecked") 64 | Class eClass = (Class )typeMap.get(type); 65 | if(null == eClass) { 66 | throw new SerializeException(String.format("Unknown entry type: %d!", type)); 67 | } else { 68 | return parse(buffer, offset + 1, length - 1,eClass); 69 | } 70 | 71 | } 72 | 73 | public static byte [] serialize(E entry) { 74 | if (entry == null){ 75 | return null; 76 | } 77 | @SuppressWarnings("unchecked") 78 | Serializer serializer = (Serializer) serializerMap.getOrDefault(entry.getClass(),serializerMap.get(Object.class)); 79 | if(serializer == null) { 80 | throw new SerializeException(String.format("Unknown entry class type: %s", entry.getClass().toString())); 81 | } 82 | byte [] bytes = new byte [serializer.size(entry) + 1]; 83 | bytes[0] = serializer.type(); 84 | serializer.serialize(entry, bytes, 1, bytes.length - 1); 85 | return bytes; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/Serializer.java: -------------------------------------------------------------------------------- 1 | package com.github.liyue2008.rpc.serialize; 2 | /** 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | public interface Serializer { 17 | /** 18 | * 计算对象序列化后的长度,主要用于申请存放序列化数据的字节数组 19 | * @param entry 待序列化的对象 20 | * @return 对象序列化后的长度 21 | */ 22 | int size(T entry); 23 | 24 | /** 25 | * 序列化对象。将给定的对象序列化成字节数组 26 | * @param entry 待序列化的对象 27 | * @param bytes 存放序列化数据的字节数组 28 | * @param offset 数组的偏移量,从这个位置开始写入序列化数据 29 | * @param length 对象序列化后的长度,也就是{@link Serializer#size(java.lang.Object)}方法的返回值。 30 | */ 31 | void serialize(T entry, byte[] bytes, int offset, int length); 32 | 33 | /** 34 | * 反序列化对象 35 | * @param bytes 存放序列化数据的字节数组 36 | * @param offset 数组的偏移量,从这个位置开始写入序列化数据 37 | * @param length 对象序列化后的长度 38 | * @return 反序列化之后生成的对象 39 | */ 40 | T parse(byte[] bytes, int offset, int length); 41 | 42 | /** 43 | * 用一个字节标识对象类型,每种类型的数据应该具有不同的类型值 44 | */ 45 | byte type(); 46 | 47 | /** 48 | * 返回序列化对象类型的Class对象。 49 | */ 50 | Class getSerializeClass(); 51 | } 52 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/MetadataSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | import com.github.liyue2008.rpc.nameservice.Metadata; 17 | import com.github.liyue2008.rpc.serialize.Serializer; 18 | 19 | import java.net.URI; 20 | import java.nio.ByteBuffer; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.Map; 25 | 26 | /** 27 | * Size of the map 2 bytes 28 | * Map entry: 29 | * Key string: 30 | * Length: 2 bytes 31 | * Serialized key bytes: variable length 32 | * Value list 33 | * List size: 2 bytes 34 | * item(URI): 35 | * Length: 2 bytes 36 | * serialized uri: variable length 37 | * item(URI): 38 | * ... 39 | * Map entry: 40 | * ... 41 | * 42 | * @author LiYue 43 | * Date: 2019/9/20 44 | */ 45 | public class MetadataSerializer implements Serializer { 46 | 47 | @Override 48 | public int size(Metadata entry) { 49 | return Short.BYTES + // Size of the map 2 bytes 50 | entry.entrySet().stream() 51 | .mapToInt(this::entrySize).sum(); 52 | } 53 | 54 | @Override 55 | public void serialize(Metadata entry, byte[] bytes, int offset, int length) { 56 | 57 | ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, length); 58 | buffer.putShort(toShortSafely(entry.size())); 59 | 60 | entry.forEach((k,v) -> { 61 | byte [] keyBytes = k.getBytes(StandardCharsets.UTF_8); 62 | buffer.putShort(toShortSafely(keyBytes.length)); 63 | buffer.put(keyBytes); 64 | 65 | buffer.putShort(toShortSafely(v.size())); 66 | for (URI uri : v) { 67 | byte [] uriBytes = uri.toASCIIString().getBytes(StandardCharsets.UTF_8); 68 | buffer.putShort(toShortSafely(uriBytes.length)); 69 | buffer.put(uriBytes); 70 | } 71 | 72 | }); 73 | } 74 | 75 | private int entrySize(Map.Entry> e) { 76 | // Map entry: 77 | return Short.BYTES + // Key string length: 2 bytes 78 | e.getKey().getBytes().length + // Serialized key bytes: variable length 79 | Short.BYTES + // List size: 2 bytes 80 | e.getValue().stream() // Value list 81 | .mapToInt(uri -> { 82 | return Short.BYTES + // Key string length: 2 bytes 83 | uri.toASCIIString().getBytes(StandardCharsets.UTF_8).length; // Serialized key bytes: variable length 84 | }).sum(); 85 | } 86 | 87 | @Override 88 | public Metadata parse(byte[] bytes, int offset, int length) { 89 | ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, length); 90 | 91 | Metadata metadata = new Metadata(); 92 | int sizeOfMap = buffer.getShort(); 93 | for (int i = 0; i < sizeOfMap; i++) { 94 | int keyLength = buffer.getShort(); 95 | byte [] keyBytes = new byte [keyLength]; 96 | buffer.get(keyBytes); 97 | String key = new String(keyBytes, StandardCharsets.UTF_8); 98 | 99 | 100 | int uriListSize = buffer.getShort(); 101 | List uriList = new ArrayList<>(uriListSize); 102 | for (int j = 0; j < uriListSize; j++) { 103 | int uriLength = buffer.getShort(); 104 | byte [] uriBytes = new byte [uriLength]; 105 | buffer.get(uriBytes); 106 | URI uri = URI.create(new String(uriBytes, StandardCharsets.UTF_8)); 107 | uriList.add(uri); 108 | } 109 | metadata.put(key, uriList); 110 | } 111 | return metadata; 112 | } 113 | 114 | @Override 115 | public byte type() { 116 | return Types.TYPE_METADATA; 117 | } 118 | 119 | @Override 120 | public Class getSerializeClass() { 121 | return Metadata.class; 122 | } 123 | 124 | private short toShortSafely(int v) { 125 | assert v < Short.MAX_VALUE; 126 | return (short) v; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/ObjectArraysSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/20 19 | */ 20 | public class ObjectArraysSerializer extends ObjectSerializer { 21 | 22 | 23 | @Override 24 | public byte type() { 25 | return Types.TYPE_OBJECT_ARRAY; 26 | } 27 | 28 | @Override 29 | public Class getSerializeClass() { 30 | return new Object[]{}.getClass(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/ObjectSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | import com.github.liyue2008.rpc.serialize.Serializer; 17 | 18 | import java.io.*; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public class ObjectSerializer implements Serializer { 25 | 26 | 27 | @Override 28 | public int size(Object entry) { 29 | return toByteArray(entry).length; 30 | } 31 | 32 | @Override 33 | public void serialize(Object entry, byte[] bytes, int offset, int length) { 34 | byte[] objBytes = toByteArray(entry); 35 | System.arraycopy(objBytes, 0, bytes, offset, objBytes.length); 36 | } 37 | 38 | @Override 39 | public Object parse(byte[] bytes, int offset, int length) { 40 | byte[] subBytes = new byte[length]; 41 | System.arraycopy(bytes,offset,subBytes,0,length); 42 | return toObject(subBytes); 43 | } 44 | 45 | @Override 46 | public byte type() { 47 | return Types.TYPE_OBJECT; 48 | } 49 | 50 | @Override 51 | public Class getSerializeClass() { 52 | return Object.class; 53 | } 54 | 55 | /** 56 | * 对象转数组 57 | * @param obj 58 | * @return 59 | */ 60 | public byte[] toByteArray (Object obj) { 61 | byte[] bytes = null; 62 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 63 | try { 64 | ObjectOutputStream oos = new ObjectOutputStream(bos); 65 | oos.writeObject(obj); 66 | oos.flush(); 67 | bytes = bos.toByteArray (); 68 | oos.close(); 69 | bos.close(); 70 | } catch (IOException ex) { 71 | ex.printStackTrace(); 72 | } 73 | return bytes; 74 | } 75 | 76 | /** 77 | * 数组转对象 78 | * @param bytes 79 | * @return 80 | */ 81 | public Object toObject (byte[] bytes) { 82 | Object obj = null; 83 | try { 84 | ByteArrayInputStream bis = new ByteArrayInputStream (bytes); 85 | ObjectInputStream ois = new ObjectInputStream (bis); 86 | obj = ois.readObject(); 87 | ois.close(); 88 | bis.close(); 89 | } catch (IOException ex) { 90 | ex.printStackTrace(); 91 | } catch (ClassNotFoundException ex) { 92 | ex.printStackTrace(); 93 | } 94 | return obj; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/RpcRequestSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | import com.github.liyue2008.rpc.client.stubs.RpcRequest; 17 | import com.github.liyue2008.rpc.serialize.Serializer; 18 | 19 | import java.nio.ByteBuffer; 20 | import java.nio.charset.StandardCharsets; 21 | 22 | /** 23 | * @author LiYue 24 | * Date: 2019/9/27 25 | */ 26 | public class RpcRequestSerializer implements Serializer { 27 | @Override 28 | public int size(RpcRequest request) { 29 | return Integer.BYTES + request.getInterfaceName().getBytes(StandardCharsets.UTF_8).length + 30 | Integer.BYTES + request.getMethodName().getBytes(StandardCharsets.UTF_8).length + 31 | Integer.BYTES + request.getSerializedArguments().length; 32 | } 33 | 34 | @Override 35 | public void serialize(RpcRequest request, byte[] bytes, int offset, int length) { 36 | ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, length); 37 | byte [] tmpBytes = request.getInterfaceName().getBytes(StandardCharsets.UTF_8); 38 | buffer.putInt(tmpBytes.length); 39 | buffer.put(tmpBytes); 40 | 41 | tmpBytes = request.getMethodName().getBytes(StandardCharsets.UTF_8); 42 | buffer.putInt(tmpBytes.length); 43 | buffer.put(tmpBytes); 44 | 45 | tmpBytes = request.getSerializedArguments(); 46 | buffer.putInt(tmpBytes.length); 47 | buffer.put(tmpBytes); 48 | } 49 | 50 | @Override 51 | public RpcRequest parse(byte[] bytes, int offset, int length) { 52 | ByteBuffer buffer = ByteBuffer.wrap(bytes, offset, length); 53 | int len = buffer.getInt(); 54 | byte [] tmpBytes = new byte[len]; 55 | buffer.get(tmpBytes); 56 | String interfaceName = new String(tmpBytes, StandardCharsets.UTF_8); 57 | 58 | len = buffer.getInt(); 59 | tmpBytes = new byte[len]; 60 | buffer.get(tmpBytes); 61 | String methodName = new String(tmpBytes, StandardCharsets.UTF_8); 62 | 63 | len = buffer.getInt(); 64 | tmpBytes = new byte[len]; 65 | buffer.get(tmpBytes); 66 | byte [] serializedArgs = tmpBytes; 67 | 68 | return new RpcRequest(interfaceName, methodName, serializedArgs); 69 | } 70 | 71 | @Override 72 | public byte type() { 73 | return Types.TYPE_RPC_REQUEST; 74 | } 75 | 76 | @Override 77 | public Class getSerializeClass() { 78 | return RpcRequest.class; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/StringSerializer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | import com.github.liyue2008.rpc.serialize.Serializer; 17 | 18 | import java.nio.charset.StandardCharsets; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public class StringSerializer implements Serializer { 25 | @Override 26 | public int size(String entry) { 27 | return entry.getBytes(StandardCharsets.UTF_8).length; 28 | } 29 | 30 | @Override 31 | public void serialize(String entry, byte[] bytes, int offset, int length) { 32 | byte [] strBytes = entry.getBytes(StandardCharsets.UTF_8); 33 | System.arraycopy(strBytes, 0, bytes, offset, strBytes.length); 34 | } 35 | 36 | @Override 37 | public String parse(byte[] bytes, int offset, int length) { 38 | return new String(bytes, offset, length, StandardCharsets.UTF_8); 39 | } 40 | 41 | @Override 42 | public byte type() { 43 | return Types.TYPE_STRING; 44 | } 45 | 46 | @Override 47 | public Class getSerializeClass() { 48 | return String.class; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/serialize/impl/Types.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.serialize.impl; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/20 19 | */ 20 | class Types { 21 | final static int TYPE_STRING = 0; 22 | final static int TYPE_OBJECT_ARRAY = 1; 23 | final static int TYPE_OBJECT = 2; 24 | final static int TYPE_METADATA = 100; 25 | final static int TYPE_RPC_REQUEST = 101; 26 | } 27 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/server/RpcRequestHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.server; 15 | 16 | import com.github.liyue2008.rpc.client.ServiceTypes; 17 | import com.github.liyue2008.rpc.client.stubs.RpcRequest; 18 | import com.github.liyue2008.rpc.serialize.SerializeSupport; 19 | import com.github.liyue2008.rpc.spi.Singleton; 20 | import com.github.liyue2008.rpc.transport.RequestHandler; 21 | import com.github.liyue2008.rpc.transport.command.Code; 22 | import com.github.liyue2008.rpc.transport.command.Command; 23 | import com.github.liyue2008.rpc.transport.command.Header; 24 | import com.github.liyue2008.rpc.transport.command.ResponseHeader; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import java.lang.reflect.Method; 29 | import java.util.HashMap; 30 | import java.util.Map; 31 | 32 | /** 33 | * @author LiYue 34 | * Date: 2019/9/23 35 | */ 36 | @Singleton 37 | public class RpcRequestHandler implements RequestHandler, ServiceProviderRegistry { 38 | private static final Logger logger = LoggerFactory.getLogger(RpcRequestHandler.class); 39 | private Map serviceProviders = new HashMap<>(); 40 | 41 | @Override 42 | public Command handle(Command requestCommand) { 43 | Header header = requestCommand.getHeader(); 44 | // 从payload中反序列化RpcRequest 45 | RpcRequest rpcRequest = SerializeSupport.parse(requestCommand.getPayload()); 46 | try { 47 | // 查找所有已注册的服务提供方,寻找rpcRequest中需要的服务 48 | Object serviceProvider = serviceProviders.get(rpcRequest.getInterfaceName()); 49 | if(serviceProvider != null) { 50 | // 找到服务提供者,利用Java反射机制调用服务的对应方法 51 | Object[] arg = SerializeSupport.parse(rpcRequest.getSerializedArguments()); 52 | Class[] paraTypes = new Class[arg.length]; 53 | for (int i = 0; i < paraTypes.length; i++) { 54 | paraTypes[i] = arg[i].getClass(); 55 | } 56 | Method method = serviceProvider.getClass().getMethod(rpcRequest.getMethodName(), paraTypes); 57 | Object result = method.invoke(serviceProvider, arg); 58 | // 把结果封装成响应命令并返回 59 | return new Command(new ResponseHeader(type(), header.getVersion(), header.getRequestId()), SerializeSupport.serialize(result)); 60 | } 61 | // 如果没找到,返回NO_PROVIDER错误响应。 62 | logger.warn("No service Provider of {}#{}(String)!", rpcRequest.getInterfaceName(), rpcRequest.getMethodName()); 63 | return new Command(new ResponseHeader(type(), header.getVersion(), header.getRequestId(), Code.NO_PROVIDER.getCode(), "No provider!"), new byte[0]); 64 | } catch (Throwable t) { 65 | // 发生异常,返回UNKNOWN_ERROR错误响应。 66 | logger.warn("Exception: ", t); 67 | return new Command(new ResponseHeader(type(), header.getVersion(), header.getRequestId(), Code.UNKNOWN_ERROR.getCode(), t.getMessage()), new byte[0]); 68 | } 69 | } 70 | 71 | @Override 72 | public int type() { 73 | return ServiceTypes.TYPE_RPC_REQUEST; 74 | } 75 | 76 | @Override 77 | public synchronized void addServiceProvider(Class serviceClass, T serviceProvider) { 78 | serviceProviders.put(serviceClass.getCanonicalName(), serviceProvider); 79 | logger.info("Add service: {}, provider: {}.", 80 | serviceClass.getCanonicalName(), 81 | serviceProvider.getClass().getCanonicalName()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/server/ServiceProviderRegistry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.server; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/29 19 | */ 20 | public interface ServiceProviderRegistry { 21 | void addServiceProvider(Class serviceClass, T serviceProvider); 22 | } 23 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/InFlightRequests.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import java.io.Closeable; 17 | import java.util.Map; 18 | import java.util.concurrent.ConcurrentHashMap; 19 | import java.util.concurrent.Executors; 20 | import java.util.concurrent.ScheduledExecutorService; 21 | import java.util.concurrent.ScheduledFuture; 22 | import java.util.concurrent.Semaphore; 23 | import java.util.concurrent.TimeUnit; 24 | import java.util.concurrent.TimeoutException; 25 | 26 | /** 27 | * @author LiYue 28 | * Date: 2019/9/20 29 | */ 30 | public class InFlightRequests implements Closeable { 31 | private final static long TIMEOUT_SEC = 10L; 32 | private final Semaphore semaphore = new Semaphore(10); 33 | private final Map futureMap = new ConcurrentHashMap<>(); 34 | private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); 35 | private final ScheduledFuture scheduledFuture; 36 | public InFlightRequests() { 37 | scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(this::removeTimeoutFutures, TIMEOUT_SEC, TIMEOUT_SEC, TimeUnit.SECONDS); 38 | } 39 | 40 | public void put(ResponseFuture responseFuture) throws InterruptedException, TimeoutException { 41 | if(semaphore.tryAcquire(TIMEOUT_SEC, TimeUnit.SECONDS)) { 42 | futureMap.put(responseFuture.getRequestId(), responseFuture); 43 | } else { 44 | throw new TimeoutException(); 45 | } 46 | } 47 | 48 | private void removeTimeoutFutures() { 49 | futureMap.entrySet().removeIf(entry -> { 50 | if( System.nanoTime() - entry.getValue().getTimestamp() > TIMEOUT_SEC * 1000000000L) { 51 | semaphore.release(); 52 | return true; 53 | } else { 54 | return false; 55 | } 56 | }); 57 | } 58 | 59 | public ResponseFuture remove(int requestId) { 60 | ResponseFuture future = futureMap.remove(requestId); 61 | if(null != future) { 62 | semaphore.release(); 63 | } 64 | return future; 65 | } 66 | 67 | @Override 68 | public void close() { 69 | scheduledFuture.cancel(true); 70 | scheduledExecutorService.shutdown(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/RequestHandler.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Command; 17 | 18 | /** 19 | * 请求处理器 20 | * @author LiYue 21 | * Date: 2019/9/20 22 | */ 23 | public interface RequestHandler { 24 | /** 25 | * 处理请求 26 | * @param requestCommand 请求命令 27 | * @return 响应命令 28 | */ 29 | Command handle(Command requestCommand); 30 | 31 | /** 32 | * 支持的请求类型 33 | */ 34 | int type(); 35 | } 36 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/RequestHandlerRegistry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import com.github.liyue2008.rpc.spi.ServiceSupport; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import java.util.Collection; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * @author LiYue 26 | * Date: 2019/9/23 27 | */ 28 | public class RequestHandlerRegistry { 29 | private static final Logger logger = LoggerFactory.getLogger(RequestHandlerRegistry.class); 30 | private Map handlerMap = new HashMap<>(); 31 | private static RequestHandlerRegistry instance = null; 32 | public static RequestHandlerRegistry getInstance() { 33 | if (null == instance) { 34 | instance = new RequestHandlerRegistry(); 35 | } 36 | return instance; 37 | } 38 | 39 | private RequestHandlerRegistry() { 40 | Collection requestHandlers = ServiceSupport.loadAll(RequestHandler.class); 41 | for (RequestHandler requestHandler : requestHandlers) { 42 | handlerMap.put(requestHandler.type(), requestHandler); 43 | logger.info("Load request handler, type: {}, class: {}.", requestHandler.type(), requestHandler.getClass().getCanonicalName()); 44 | } 45 | } 46 | 47 | 48 | public RequestHandler get(int type) { 49 | return handlerMap.get(type); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/ResponseFuture.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Command; 17 | 18 | import java.util.concurrent.CompletableFuture; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public class ResponseFuture { 25 | private final int requestId; 26 | private final CompletableFuture future; 27 | private final long timestamp; 28 | 29 | public ResponseFuture(int requestId, CompletableFuture future) { 30 | this.requestId = requestId; 31 | this.future = future; 32 | timestamp = System.nanoTime(); 33 | } 34 | 35 | public int getRequestId() { 36 | return requestId; 37 | } 38 | 39 | public CompletableFuture getFuture() { 40 | return future; 41 | } 42 | 43 | long getTimestamp() { 44 | return timestamp; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/Transport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Command; 17 | 18 | import java.util.concurrent.CompletableFuture; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public interface Transport { 25 | /** 26 | * 发送请求命令 27 | * @param request 请求命令 28 | * @return 返回值是一个Future,Future 29 | */ 30 | CompletableFuture send(Command request); 31 | } 32 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/TransportClient.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | import com.github.liyue2008.rpc.transport.Transport; 17 | 18 | import java.io.Closeable; 19 | import java.net.SocketAddress; 20 | import java.util.concurrent.TimeoutException; 21 | 22 | /** 23 | * @author LiYue 24 | * Date: 2019/9/25 25 | */ 26 | public interface TransportClient extends Closeable { 27 | Transport createTransport(SocketAddress address, long connectionTimeout) throws InterruptedException, TimeoutException; 28 | @Override 29 | void close(); 30 | } 31 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/TransportServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/25 19 | */ 20 | public interface TransportServer { 21 | void start(RequestHandlerRegistry requestHandlerRegistry, int port) throws Exception; 22 | void stop(); 23 | } 24 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/command/Code.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.command; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | /** 20 | * @author LiYue 21 | * Date: 2019/9/23 22 | */ 23 | public enum Code { 24 | 25 | SUCCESS(0, "SUCCESS"), 26 | NO_PROVIDER(-2, "NO_PROVIDER"), 27 | UNKNOWN_ERROR(-1, "UNKNOWN_ERROR"); 28 | 29 | private static Map codes = new HashMap<>(); 30 | private int code; 31 | private String message; 32 | 33 | static { 34 | for (Code code : Code.values()) { 35 | codes.put(code.code, code); 36 | } 37 | } 38 | 39 | Code(int code, String message) { 40 | this.code = code; 41 | this.message = message; 42 | } 43 | 44 | public static Code valueOf(int code) { 45 | return codes.get(code); 46 | } 47 | 48 | public int getCode() { 49 | return code; 50 | } 51 | 52 | public String getMessage(Object... args) { 53 | if (args.length < 1) { 54 | return message; 55 | } 56 | return String.format(message, args); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/command/Command.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.command; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/20 19 | */ 20 | public class Command { 21 | protected Header header; 22 | private byte [] payload; 23 | 24 | public Command(Header header, byte [] payload) { 25 | this.header = header; 26 | this.payload = payload; 27 | } 28 | public Header getHeader() { 29 | return header; 30 | } 31 | 32 | public void setHeader(Header header) { 33 | this.header = header; 34 | } 35 | 36 | public byte [] getPayload() { 37 | return payload; 38 | } 39 | 40 | public void setPayload(byte [] payload) { 41 | this.payload = payload; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/command/Header.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.command; 15 | 16 | /** 17 | * @author LiYue 18 | * Date: 2019/9/20 19 | */ 20 | public class Header { 21 | private int requestId; 22 | private int version; 23 | private int type; 24 | 25 | public Header() {} 26 | public Header(int type, int version, int requestId) { 27 | this.requestId = requestId; 28 | this.type = type; 29 | this.version = version; 30 | } 31 | public int getRequestId() { 32 | return requestId; 33 | } 34 | 35 | public void setRequestId(int requestId) { 36 | this.requestId = requestId; 37 | } 38 | 39 | public int getVersion() { 40 | return version; 41 | } 42 | 43 | public void setVersion(int version) { 44 | this.version = version; 45 | } 46 | 47 | public int getType() { 48 | return type; 49 | } 50 | 51 | public int length() { 52 | return Integer.BYTES + Integer.BYTES + Integer.BYTES; 53 | } 54 | 55 | public void setType(int type) { 56 | this.type = type; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/command/ResponseHeader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.command; 15 | 16 | import java.nio.charset.StandardCharsets; 17 | 18 | /** 19 | * @author LiYue 20 | * Date: 2019/9/20 21 | */ 22 | public class ResponseHeader extends Header { 23 | private int code; 24 | private String error; 25 | 26 | public ResponseHeader(int type, int version, int requestId, Throwable throwable) { 27 | this(type, version, requestId, Code.UNKNOWN_ERROR.getCode(), throwable.getMessage()); 28 | } 29 | 30 | public ResponseHeader(int type, int version, int requestId) { 31 | this(type, version, requestId, Code.SUCCESS.getCode(), null); 32 | } 33 | 34 | public ResponseHeader( int type, int version, int requestId , int code, String error) { 35 | super(type, version, requestId); 36 | this.code = code; 37 | this.error = error; 38 | } 39 | 40 | 41 | 42 | @Override 43 | public int length() { 44 | return Integer.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES + 45 | Integer.BYTES + 46 | (error == null ? 0 : error.getBytes(StandardCharsets.UTF_8).length); 47 | } 48 | 49 | public int getCode() { 50 | return code; 51 | } 52 | 53 | public void setCode(int code) { 54 | this.code = code; 55 | } 56 | 57 | public String getError() { 58 | return error; 59 | } 60 | 61 | public void setError(String error) { 62 | this.error = error; 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/CommandDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Command; 17 | import com.github.liyue2008.rpc.transport.command.Header; 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.channel.ChannelHandlerContext; 20 | import io.netty.handler.codec.ByteToMessageDecoder; 21 | 22 | import java.util.List; 23 | 24 | /** 25 | * @author LiYue 26 | * Date: 2019/9/23 27 | */ 28 | public abstract class CommandDecoder extends ByteToMessageDecoder { 29 | private static final int LENGTH_FIELD_LENGTH = Integer.BYTES; 30 | @Override 31 | protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List list) { 32 | if (!byteBuf.isReadable(LENGTH_FIELD_LENGTH)) { 33 | return; 34 | } 35 | byteBuf.markReaderIndex(); 36 | int length = byteBuf.readInt() - LENGTH_FIELD_LENGTH; 37 | 38 | if (byteBuf.readableBytes() < length) { 39 | byteBuf.resetReaderIndex(); 40 | return; 41 | } 42 | 43 | Header header = decodeHeader(channelHandlerContext, byteBuf); 44 | int payloadLength = length - header.length(); 45 | byte [] payload = new byte[payloadLength]; 46 | byteBuf.readBytes(payload); 47 | list.add(new Command(header, payload)); 48 | } 49 | 50 | protected abstract Header decodeHeader(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) ; 51 | } 52 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/CommandEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Command; 17 | import com.github.liyue2008.rpc.transport.command.Header; 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.channel.ChannelHandlerContext; 20 | import io.netty.handler.codec.MessageToByteEncoder; 21 | 22 | /** 23 | * @author LiYue 24 | * Date: 2019/9/23 25 | */ 26 | public abstract class CommandEncoder extends MessageToByteEncoder { 27 | 28 | @Override 29 | protected void encode(ChannelHandlerContext channelHandlerContext, Object o, ByteBuf byteBuf) throws Exception { 30 | if(!(o instanceof Command)) { 31 | throw new Exception(String.format("Unknown type: %s!", o.getClass().getCanonicalName())); 32 | } 33 | 34 | Command command = (Command) o; 35 | byteBuf.writeInt(Integer.BYTES + command.getHeader().length() + command.getPayload().length); 36 | encodeHeader(channelHandlerContext, command.getHeader(), byteBuf); 37 | byteBuf.writeBytes(command.getPayload()); 38 | 39 | 40 | } 41 | 42 | protected void encodeHeader(ChannelHandlerContext channelHandlerContext, Header header, ByteBuf byteBuf) throws Exception { 43 | byteBuf.writeInt(header.getType()); 44 | byteBuf.writeInt(header.getVersion()); 45 | byteBuf.writeInt(header.getRequestId()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/NettyClient.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.InFlightRequests; 17 | import com.github.liyue2008.rpc.transport.Transport; 18 | import com.github.liyue2008.rpc.transport.TransportClient; 19 | import io.netty.bootstrap.Bootstrap; 20 | import io.netty.buffer.PooledByteBufAllocator; 21 | import io.netty.channel.Channel; 22 | import io.netty.channel.ChannelFuture; 23 | import io.netty.channel.ChannelHandler; 24 | import io.netty.channel.ChannelInitializer; 25 | import io.netty.channel.ChannelOption; 26 | import io.netty.channel.EventLoopGroup; 27 | import io.netty.channel.epoll.Epoll; 28 | import io.netty.channel.epoll.EpollEventLoopGroup; 29 | import io.netty.channel.epoll.EpollSocketChannel; 30 | import io.netty.channel.nio.NioEventLoopGroup; 31 | import io.netty.channel.socket.nio.NioSocketChannel; 32 | 33 | import java.net.SocketAddress; 34 | import java.util.LinkedList; 35 | import java.util.List; 36 | import java.util.concurrent.TimeoutException; 37 | 38 | /** 39 | * @author LiYue 40 | * Date: 2019/9/20 41 | */ 42 | public class NettyClient implements TransportClient { 43 | private EventLoopGroup ioEventGroup; 44 | private Bootstrap bootstrap; 45 | private final InFlightRequests inFlightRequests; 46 | private List channels = new LinkedList<>(); 47 | 48 | public NettyClient() { 49 | inFlightRequests = new InFlightRequests(); 50 | } 51 | 52 | private Bootstrap newBootstrap(ChannelHandler channelHandler, EventLoopGroup ioEventGroup) { 53 | Bootstrap bootstrap = new Bootstrap(); 54 | bootstrap.channel(Epoll.isAvailable() ? EpollSocketChannel.class : NioSocketChannel.class) 55 | .group(ioEventGroup) 56 | .handler(channelHandler) 57 | .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 58 | return bootstrap; 59 | } 60 | 61 | @Override 62 | public Transport createTransport(SocketAddress address, long connectionTimeout) throws InterruptedException, TimeoutException { 63 | return new NettyTransport(createChannel(address, connectionTimeout), inFlightRequests); 64 | } 65 | 66 | private synchronized Channel createChannel(SocketAddress address, long connectionTimeout) throws InterruptedException, TimeoutException { 67 | if (address == null) { 68 | throw new IllegalArgumentException("address must not be null!"); 69 | } 70 | if (ioEventGroup == null) { 71 | ioEventGroup = newIoEventGroup(); 72 | } 73 | if (bootstrap == null){ 74 | ChannelHandler channelHandlerPipeline = newChannelHandlerPipeline(); 75 | bootstrap = newBootstrap(channelHandlerPipeline, ioEventGroup); 76 | } 77 | ChannelFuture channelFuture; 78 | Channel channel; 79 | channelFuture = bootstrap.connect(address); 80 | if (!channelFuture.await(connectionTimeout)) { 81 | throw new TimeoutException(); 82 | } 83 | channel = channelFuture.channel(); 84 | if (channel == null || !channel.isActive()) { 85 | throw new IllegalStateException(); 86 | } 87 | channels.add(channel); 88 | return channel; 89 | } 90 | private ChannelHandler newChannelHandlerPipeline() { 91 | return new ChannelInitializer() { 92 | @Override 93 | protected void initChannel(Channel channel) { 94 | channel.pipeline() 95 | .addLast(new ResponseDecoder()) 96 | .addLast(new RequestEncoder()) 97 | .addLast(new ResponseInvocation(inFlightRequests)); 98 | } 99 | }; 100 | } 101 | 102 | private EventLoopGroup newIoEventGroup() { 103 | 104 | if (Epoll.isAvailable()) { 105 | return new EpollEventLoopGroup(); 106 | } else { 107 | return new NioEventLoopGroup(); 108 | } 109 | } 110 | 111 | @Override 112 | public void close() { 113 | for (Channel channel : channels) { 114 | if(null != channel) { 115 | channel.close(); 116 | } 117 | } 118 | if (ioEventGroup != null) { 119 | ioEventGroup.shutdownGracefully(); 120 | } 121 | inFlightRequests.close(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/NettyServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.RequestHandlerRegistry; 17 | import com.github.liyue2008.rpc.transport.TransportServer; 18 | import io.netty.bootstrap.ServerBootstrap; 19 | import io.netty.buffer.PooledByteBufAllocator; 20 | import io.netty.channel.Channel; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelInitializer; 23 | import io.netty.channel.ChannelOption; 24 | import io.netty.channel.EventLoopGroup; 25 | import io.netty.channel.epoll.Epoll; 26 | import io.netty.channel.epoll.EpollEventLoopGroup; 27 | import io.netty.channel.epoll.EpollServerSocketChannel; 28 | import io.netty.channel.nio.NioEventLoopGroup; 29 | import io.netty.channel.socket.nio.NioServerSocketChannel; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | /** 34 | * @author LiYue 35 | * Date: 2019/9/20 36 | */ 37 | public class NettyServer implements TransportServer { 38 | private static final Logger logger = LoggerFactory.getLogger(NettyServer.class); 39 | private int port; 40 | private EventLoopGroup acceptEventGroup; 41 | private EventLoopGroup ioEventGroup; 42 | private Channel channel; 43 | private RequestHandlerRegistry requestHandlerRegistry; 44 | 45 | @Override 46 | public void start(RequestHandlerRegistry requestHandlerRegistry, int port) throws Exception { 47 | this.port = port; 48 | this.requestHandlerRegistry = requestHandlerRegistry; 49 | EventLoopGroup acceptEventGroup = newEventLoopGroup(); 50 | EventLoopGroup ioEventGroup = newEventLoopGroup(); 51 | ChannelHandler channelHandlerPipeline = newChannelHandlerPipeline(); 52 | ServerBootstrap serverBootstrap = newBootstrap(channelHandlerPipeline, acceptEventGroup, ioEventGroup); 53 | Channel channel = doBind(serverBootstrap); 54 | 55 | this.acceptEventGroup = acceptEventGroup; 56 | this.ioEventGroup = ioEventGroup; 57 | this.channel = channel; 58 | 59 | } 60 | 61 | @Override 62 | public void stop() { 63 | if (acceptEventGroup != null) { 64 | acceptEventGroup.shutdownGracefully(); 65 | } 66 | if (ioEventGroup != null) { 67 | ioEventGroup.shutdownGracefully(); 68 | } 69 | if (channel != null) { 70 | channel.close(); 71 | } 72 | } 73 | 74 | private Channel doBind(ServerBootstrap serverBootstrap) throws Exception { 75 | return serverBootstrap.bind(port) 76 | .sync() 77 | .channel(); 78 | } 79 | 80 | private EventLoopGroup newEventLoopGroup() { 81 | if (Epoll.isAvailable()) { 82 | return new EpollEventLoopGroup(); 83 | } else { 84 | return new NioEventLoopGroup(); 85 | } 86 | } 87 | 88 | private ChannelHandler newChannelHandlerPipeline() { 89 | return new ChannelInitializer() { 90 | @Override 91 | protected void initChannel(Channel channel) { 92 | channel.pipeline() 93 | .addLast(new RequestDecoder()) 94 | .addLast(new ResponseEncoder()) 95 | .addLast(new RequestInvocation(requestHandlerRegistry)); 96 | } 97 | }; 98 | } 99 | 100 | private ServerBootstrap newBootstrap(ChannelHandler channelHandler, EventLoopGroup acceptEventGroup, EventLoopGroup ioEventGroup) { 101 | ServerBootstrap serverBootstrap = new ServerBootstrap(); 102 | serverBootstrap.channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) 103 | .group(acceptEventGroup, ioEventGroup) 104 | .childHandler(channelHandler) 105 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); 106 | return serverBootstrap; 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/NettyTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.InFlightRequests; 17 | import com.github.liyue2008.rpc.transport.ResponseFuture; 18 | import com.github.liyue2008.rpc.transport.Transport; 19 | import com.github.liyue2008.rpc.transport.command.Command; 20 | import io.netty.channel.Channel; 21 | import io.netty.channel.ChannelFutureListener; 22 | 23 | import java.util.concurrent.CompletableFuture; 24 | 25 | /** 26 | * @author LiYue 27 | * Date: 2019/9/20 28 | */ 29 | public class NettyTransport implements Transport { 30 | private final Channel channel; 31 | private final InFlightRequests inFlightRequests; 32 | 33 | NettyTransport(Channel channel, InFlightRequests inFlightRequests) { 34 | this.channel = channel; 35 | this.inFlightRequests = inFlightRequests; 36 | } 37 | 38 | 39 | 40 | 41 | @Override 42 | public CompletableFuture send(Command request) { 43 | // 构建返回值 44 | CompletableFuture completableFuture = new CompletableFuture<>(); 45 | try { 46 | // 将在途请求放到inFlightRequests中 47 | inFlightRequests.put(new ResponseFuture(request.getHeader().getRequestId(), completableFuture)); 48 | // 发送命令 49 | channel.writeAndFlush(request).addListener((ChannelFutureListener) channelFuture -> { 50 | // 处理发送失败的情况 51 | if (!channelFuture.isSuccess()) { 52 | completableFuture.completeExceptionally(channelFuture.cause()); 53 | channel.close(); 54 | } 55 | }); 56 | } catch (Throwable t) { 57 | // 处理发送异常 58 | inFlightRequests.remove(request.getHeader().getRequestId()); 59 | completableFuture.completeExceptionally(t); 60 | } 61 | return completableFuture; 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/RequestDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Header; 17 | import io.netty.buffer.ByteBuf; 18 | import io.netty.channel.ChannelHandlerContext; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public class RequestDecoder extends CommandDecoder { 25 | 26 | @Override 27 | protected Header decodeHeader(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) { 28 | return new Header( 29 | byteBuf.readInt(), 30 | byteBuf.readInt(), 31 | byteBuf.readInt() 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/RequestEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Header; 17 | import io.netty.buffer.ByteBuf; 18 | import io.netty.channel.ChannelHandlerContext; 19 | 20 | /** 21 | * @author LiYue 22 | * Date: 2019/9/20 23 | */ 24 | public class RequestEncoder extends CommandEncoder { 25 | @Override 26 | protected void encodeHeader(ChannelHandlerContext channelHandlerContext, Header header, ByteBuf byteBuf) throws Exception { 27 | super.encodeHeader(channelHandlerContext, header, byteBuf); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/RequestInvocation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.RequestHandler; 17 | import com.github.liyue2008.rpc.transport.RequestHandlerRegistry; 18 | import com.github.liyue2008.rpc.transport.command.Command; 19 | import io.netty.channel.Channel; 20 | import io.netty.channel.ChannelFutureListener; 21 | import io.netty.channel.ChannelHandler; 22 | import io.netty.channel.ChannelHandlerContext; 23 | import io.netty.channel.SimpleChannelInboundHandler; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * @author LiYue 29 | * Date: 2019/9/20 30 | */ 31 | @ChannelHandler.Sharable 32 | public class RequestInvocation extends SimpleChannelInboundHandler { 33 | private static final Logger logger = LoggerFactory.getLogger(RequestInvocation.class); 34 | private final RequestHandlerRegistry requestHandlerRegistry; 35 | 36 | RequestInvocation(RequestHandlerRegistry requestHandlerRegistry) { 37 | this.requestHandlerRegistry = requestHandlerRegistry; 38 | } 39 | 40 | @Override 41 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, Command request) throws Exception { 42 | RequestHandler handler = requestHandlerRegistry.get(request.getHeader().getType()); 43 | if(null != handler) { 44 | Command response = handler.handle(request); 45 | if(null != response) { 46 | channelHandlerContext.writeAndFlush(response).addListener((ChannelFutureListener) channelFuture -> { 47 | if (!channelFuture.isSuccess()) { 48 | logger.warn("Write response failed!", channelFuture.cause()); 49 | channelHandlerContext.channel().close(); 50 | } 51 | }); 52 | } else { 53 | logger.warn("Response is null!"); 54 | } 55 | } else { 56 | throw new Exception(String.format("No handler for request with type: %d!", request.getHeader().getType())); 57 | } 58 | } 59 | 60 | @Override 61 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 62 | logger.warn("Exception: ", cause); 63 | 64 | super.exceptionCaught(ctx, cause); 65 | Channel channel = ctx.channel(); 66 | if(channel.isActive())ctx.close(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/ResponseDecoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Header; 17 | import com.github.liyue2008.rpc.transport.command.ResponseHeader; 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.channel.ChannelHandlerContext; 20 | import io.netty.handler.codec.ByteToMessageDecoder; 21 | 22 | import java.nio.charset.StandardCharsets; 23 | import java.util.List; 24 | 25 | /** 26 | * @author LiYue 27 | * Date: 2019/9/20 28 | */ 29 | public class ResponseDecoder extends CommandDecoder { 30 | 31 | @Override 32 | protected Header decodeHeader(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) { 33 | int type = byteBuf.readInt(); 34 | int version = byteBuf.readInt(); 35 | int requestId = byteBuf.readInt(); 36 | int code = byteBuf.readInt(); 37 | int errorLength = byteBuf.readInt(); 38 | byte [] errorBytes = new byte[errorLength]; 39 | byteBuf.readBytes(errorBytes); 40 | String error = new String(errorBytes, StandardCharsets.UTF_8); 41 | return new ResponseHeader( 42 | type, version, requestId, code, error 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/ResponseEncoder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.command.Header; 17 | import com.github.liyue2008.rpc.transport.command.ResponseHeader; 18 | import io.netty.buffer.ByteBuf; 19 | import io.netty.channel.ChannelHandlerContext; 20 | import io.netty.handler.codec.MessageToByteEncoder; 21 | 22 | import java.nio.charset.StandardCharsets; 23 | 24 | /** 25 | * @author LiYue 26 | * Date: 2019/9/20 27 | */ 28 | public class ResponseEncoder extends CommandEncoder { 29 | @Override 30 | protected void encodeHeader(ChannelHandlerContext channelHandlerContext, Header header, ByteBuf byteBuf) throws Exception { 31 | super.encodeHeader(channelHandlerContext, header, byteBuf); 32 | if(header instanceof ResponseHeader) { 33 | ResponseHeader responseHeader = (ResponseHeader) header; 34 | byteBuf.writeInt(responseHeader.getCode()); 35 | int errorLength = header.length() - (Integer.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES + 36 | Integer.BYTES); 37 | byteBuf.writeInt(errorLength); 38 | byteBuf.writeBytes(responseHeader.getError() == null ? new byte[0]: responseHeader.getError().getBytes(StandardCharsets.UTF_8)); 39 | } else { 40 | throw new Exception(String.format("Invalid header type: %s!", header.getClass().getCanonicalName())); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rpc-netty/src/main/java/com/github/liyue2008/rpc/transport/netty/ResponseInvocation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.transport.netty; 15 | 16 | import com.github.liyue2008.rpc.transport.InFlightRequests; 17 | import com.github.liyue2008.rpc.transport.ResponseFuture; 18 | import com.github.liyue2008.rpc.transport.command.Command; 19 | import io.netty.channel.Channel; 20 | import io.netty.channel.ChannelHandler; 21 | import io.netty.channel.ChannelHandlerContext; 22 | import io.netty.channel.SimpleChannelInboundHandler; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | /** 27 | * @author LiYue 28 | * Date: 2019/9/20 29 | */ 30 | @ChannelHandler.Sharable 31 | public class ResponseInvocation extends SimpleChannelInboundHandler { 32 | private static final Logger logger = LoggerFactory.getLogger(ResponseInvocation.class); 33 | private final InFlightRequests inFlightRequests; 34 | 35 | ResponseInvocation(InFlightRequests inFlightRequests) { 36 | this.inFlightRequests = inFlightRequests; 37 | } 38 | 39 | @Override 40 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, Command response) { 41 | ResponseFuture future = inFlightRequests.remove(response.getHeader().getRequestId()); 42 | if(null != future) { 43 | future.getFuture().complete(response); 44 | } else { 45 | logger.warn("Drop response: {}", response); 46 | } 47 | } 48 | 49 | @Override 50 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 51 | logger.warn("Exception: ", cause); 52 | super.exceptionCaught(ctx, cause); 53 | Channel channel = ctx.channel(); 54 | if(channel.isActive())ctx.close(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.NameService: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.nameservice.LocalFileNameService -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.RpcAccessPoint: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.NettyRpcAccessPoint -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.client.StubFactory: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.client.CGLibDynamicStubFactory -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.serialize.Serializer: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.serialize.impl.MetadataSerializer 2 | com.github.liyue2008.rpc.serialize.impl.StringSerializer 3 | com.github.liyue2008.rpc.serialize.impl.RpcRequestSerializer 4 | com.github.liyue2008.rpc.serialize.impl.ObjectArraysSerializer 5 | com.github.liyue2008.rpc.serialize.impl.ObjectSerializer 6 | -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.server.ServiceProviderRegistry: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.server.RpcRequestHandler -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.transport.RequestHandler: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.server.RpcRequestHandler -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.transport.TransportClient: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.transport.netty.NettyClient -------------------------------------------------------------------------------- /rpc-netty/src/main/resources/META-INF/services/com.github.liyue2008.rpc.transport.TransportServer: -------------------------------------------------------------------------------- 1 | com.github.liyue2008.rpc.transport.netty.NettyServer -------------------------------------------------------------------------------- /server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 20 | 21 | simple-rpc-framework 22 | com.github.liyue2008 23 | 1.0-SNAPSHOT 24 | 25 | 4.0.0 26 | 27 | server 28 | 29 | 30 | 31 | com.github.liyue2008 32 | hello-service-api 33 | ${project.version} 34 | 35 | 36 | com.github.liyue2008 37 | rpc-api 38 | ${project.version} 39 | 40 | 41 | org.slf4j 42 | slf4j-api 43 | 44 | 45 | org.slf4j 46 | slf4j-simple 47 | runtime 48 | 49 | 50 | com.github.liyue2008 51 | rpc-netty 52 | ${project.version} 53 | runtime 54 | 55 | 56 | 57 | 58 | 59 | org.apache.maven.plugins 60 | maven-dependency-plugin 61 | 62 | 63 | copy-dependencies 64 | prepare-package 65 | 66 | copy-dependencies 67 | 68 | 69 | 70 | ${project.build.directory}/libs 71 | 72 | 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-assembly-plugin 79 | 80 | 81 | package 82 | 83 | single 84 | 85 | 86 | 87 | 88 | 89 | com.github.liyue2008.rpc.server.Server 90 | 91 | 92 | 93 | 94 | jar-with-dependencies 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /server/src/main/java/com/github/liyue2008/rpc/server/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.server; 15 | 16 | import com.github.liyue2008.rpc.hello.HelloService; 17 | import com.github.liyue2008.rpc.hello.entity.HelloRequest; 18 | import com.github.liyue2008.rpc.hello.entity.HelloResult; 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | 22 | /** 23 | * @author LiYue 24 | * Date: 2019/9/20 25 | */ 26 | public class HelloServiceImpl implements HelloService { 27 | private static final Logger logger = LoggerFactory.getLogger(HelloServiceImpl.class); 28 | 29 | @Override 30 | public String hello(String name) { 31 | logger.info("HelloServiceImpl收到: {}.", name); 32 | String ret = "Hello, " + name; 33 | logger.info("HelloServiceImpl返回: {}.", ret); 34 | return ret; 35 | } 36 | 37 | @Override 38 | public HelloResult helloMoreResult(String name, String value) { 39 | 40 | logger.info("HelloServiceImpl收到: {}.", name,value); 41 | HelloResult result = new HelloResult(); 42 | result.setSuccess(true); 43 | result.setResult("Success"); 44 | result.setResultCode("1"); 45 | logger.info("HelloServiceImpl返回: {}.", result.toString()); 46 | 47 | return result; 48 | } 49 | 50 | @Override 51 | public HelloResult helloMoreResult(HelloRequest request) { 52 | 53 | logger.info("HelloServiceImpl收到: {}.", request.toString()); 54 | HelloResult result = new HelloResult(); 55 | result.setSuccess(true); 56 | result.setResult("Success"); 57 | result.setResultCode("1"); 58 | logger.info("HelloServiceImpl返回: {}.", result.toString()); 59 | return result; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/src/main/java/com/github/liyue2008/rpc/server/Server.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package com.github.liyue2008.rpc.server; 15 | 16 | import com.github.liyue2008.rpc.NameService; 17 | import com.github.liyue2008.rpc.RpcAccessPoint; 18 | import com.github.liyue2008.rpc.hello.HelloService; 19 | import com.github.liyue2008.rpc.spi.ServiceSupport; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | import java.io.Closeable; 24 | import java.io.File; 25 | import java.net.URI; 26 | 27 | /** 28 | * @author LiYue 29 | * Date: 2019/9/20 30 | */ 31 | public class Server { 32 | private static final Logger logger = LoggerFactory.getLogger(Server.class); 33 | public static void main(String [] args) throws Exception { 34 | 35 | String serviceName = HelloService.class.getCanonicalName(); 36 | File tmpDirFile = new File(System.getProperty("java.io.tmpdir")); 37 | File file = new File(tmpDirFile, "simple_rpc_name_service.data"); 38 | HelloService helloService = new HelloServiceImpl(); 39 | logger.info("创建并启动RpcAccessPoint..."); 40 | try(RpcAccessPoint rpcAccessPoint = ServiceSupport.load(RpcAccessPoint.class); 41 | Closeable ignored = rpcAccessPoint.startServer()) { 42 | NameService nameService = rpcAccessPoint.getNameService(file.toURI()); 43 | assert nameService != null; 44 | logger.info("向RpcAccessPoint注册{}服务...", serviceName); 45 | URI uri = rpcAccessPoint.addServiceProvider(helloService, HelloService.class); 46 | logger.info("服务名: {}, 向NameService注册...", serviceName); 47 | nameService.registerService(serviceName, uri); 48 | logger.info("开始提供服务,按任何键退出."); 49 | //noinspection ResultOfMethodCallIgnored 50 | System.in.read(); 51 | logger.info("Bye!"); 52 | } 53 | } 54 | 55 | } 56 | --------------------------------------------------------------------------------