├── .gitignore
├── LICENSE
├── README.md
├── iris
├── .gitignore
├── README.md
├── iris-bom
│ └── pom.xml
├── iris-client
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── client
│ │ │ ├── ConnectManager.java
│ │ │ ├── IConnectManager.java
│ │ │ ├── IRpcClient.java
│ │ │ ├── RpcClient.java
│ │ │ ├── RpcClientHandler.java
│ │ │ ├── RpcClientInitializer.java
│ │ │ ├── RpcFuture.java
│ │ │ ├── RpcInvokeInterceptor.java
│ │ │ └── RpcRequestHolder.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── client
│ │ │ ├── ClientTest.java
│ │ │ └── bytebuddy
│ │ │ ├── ByteBuddyTest.java
│ │ │ └── GeneralInterceptor.java
│ │ └── resources
│ │ └── iris.properties
├── iris-core
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── leiwei2094
│ │ │ │ └── iris
│ │ │ │ └── core
│ │ │ │ ├── Endpoint.java
│ │ │ │ ├── HelloService.java
│ │ │ │ ├── IHelloService.java
│ │ │ │ ├── IpHelper.java
│ │ │ │ ├── IrisConfig.java
│ │ │ │ ├── KeyValue.java
│ │ │ │ ├── annotation
│ │ │ │ ├── Reference.java
│ │ │ │ └── Service.java
│ │ │ │ └── loadbalance
│ │ │ │ ├── ILoadBalance.java
│ │ │ │ ├── RandomLoadBalance.java
│ │ │ │ └── SelectFirstLoadBalance.java
│ │ └── resources
│ │ │ └── META-INF
│ │ │ └── extensions
│ │ │ └── com.leibangzhu.iris.core.loadbalance.ILoadBalance
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── leiwei2094
│ │ └── iris
│ │ └── core
│ │ └── Test1.java
├── iris-parent
│ └── pom.xml
├── iris-protocol
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── leiwei2094
│ │ └── iris
│ │ └── protocol
│ │ ├── RpcDecoder.java
│ │ ├── RpcEncoder.java
│ │ ├── RpcRequest.java
│ │ ├── RpcResponse.java
│ │ └── SerializationUtil.java
├── iris-registry
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── registry
│ │ │ ├── EtcdRegistry.java
│ │ │ ├── IEventCallback.java
│ │ │ ├── IRegistry.java
│ │ │ └── RegistryEvent.java
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── leiwei2094
│ │ └── iris
│ │ └── registry
│ │ └── etcd
│ │ ├── EtcdRegistryTest.java
│ │ ├── GetTest.java
│ │ ├── IpHelperTest.java
│ │ ├── LeaseTest.java
│ │ ├── PutTest.java
│ │ └── WatchTest.java
├── iris-server
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── server
│ │ │ ├── RpcServer.java
│ │ │ ├── RpcServerHandler.java
│ │ │ └── RpcServerInitializer.java
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── leiwei2094
│ │ └── iris
│ │ └── server
│ │ └── ServerTest.java
├── iris-spring-boot
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── leiwei2094
│ │ │ │ └── iris
│ │ │ │ └── springboot
│ │ │ │ ├── ServiceAnnotationBeanFactoryPostProcessor.java
│ │ │ │ ├── ServiceAnnotationScanner.java
│ │ │ │ ├── config
│ │ │ │ └── IrisAutoConfiguration.java
│ │ │ │ └── properties
│ │ │ │ ├── RegistryProperties.java
│ │ │ │ └── ServerProperties.java
│ │ └── resources
│ │ │ ├── META-INF
│ │ │ └── spring.factories
│ │ │ └── application.properties.sample
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── springboot
│ │ │ ├── ClientApplication.java
│ │ │ ├── ClientTest.java
│ │ │ ├── Foo.java
│ │ │ ├── HelloService.java
│ │ │ └── ServerApplication.java
│ │ └── resources
│ │ ├── application-client.properties
│ │ ├── application-server.properties
│ │ └── iris.properties
├── iris-spring
│ ├── pom.xml
│ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── spring
│ │ │ ├── IrisApplicationListener.java
│ │ │ ├── ReferenceAnnotationBeanPostProcessor.java
│ │ │ └── ServiceAnnotationBeanPostProcessor.java
│ │ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── leiwei2094
│ │ │ └── iris
│ │ │ └── spring
│ │ │ ├── Baz.java
│ │ │ ├── HelloService.java
│ │ │ ├── XmlClient.java
│ │ │ └── XmlServer.java
│ │ └── resources
│ │ ├── beans-client.xml
│ │ └── beans-server.xml
└── pom.xml
└── samples
├── .gitignore
├── demo-a
├── build.gradle
├── demo-a-api
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── leibangzhu
│ │ └── iris
│ │ └── demoa
│ │ └── api
│ │ └── IHelloService.java
├── demo-a-service
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── leibangzhu
│ │ │ └── iris
│ │ │ └── demoa
│ │ │ └── service
│ │ │ ├── App.java
│ │ │ ├── AppConfiguration.java
│ │ │ ├── HelloService.java
│ │ │ ├── aspect
│ │ │ └── LogAspect.java
│ │ │ └── service
│ │ │ └── HelloService.java
│ │ └── resources
│ │ ├── application.properties
│ │ └── dubbo-provider.xml
└── settings.gradle
└── demo-b
├── build.gradle
├── settings.gradle
└── src
└── main
├── java
└── com
│ └── qibeitech
│ └── demob
│ ├── App.java
│ ├── AppConfiguration.java
│ ├── Bar.java
│ ├── Foo.java
│ ├── ITestService.java
│ ├── TestConfiguration.java
│ └── TestService.java
└── resources
├── application.properties
├── dubbo-consumer.xml
└── dubbo-provider.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 | *.iml
4 |
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Lei Wei
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iris
2 |
3 | 一个基于Java的RPC框架。目前可以看成是mini版的Dubbo。有注册中心,提供服务的注册,发现和负载均衡。
4 |
5 | * 网络通信: Netty4
6 | * 注册中心: etcd,可扩展
7 | * 动态代理: byte-buddy
8 | * 序列化: Protobuff(Protostuff)
9 | * 可以脱离Spring,提供API调用。
10 | * 集成Spring,提供XML,Java配置
11 | * 提供Spring Boot Starter
12 | * 提供SPI机制,实现微内核加插件的架构。实现可扩展,开发者可以为iris开发组件,以插件的形式集成到iris中。插件的加载使用另一个微容器框架见[coco](https://github.com/vangoleo/coco)项目。该项目fork于阿里的[cooma](https://github.com/alibaba/cooma)。
13 |
14 | # Todo:
15 | * 支持优雅停机,不依赖Spring和Web容器。
16 | * 支持服务延迟暴露
17 | * 支持超时和重试配置
18 | * 添加监控系统,使用Prometheus
19 | * 更好的支持容器环境
20 |
21 | # How to use
22 | iris支持以下使用方式:
23 | 1. 原生API形式,不依赖Spring,非Spring项目也可以使用
24 | 2. Spring配置方式,和Spring很好的集成
25 | 3. Spring Boot配置方式,提供了一个spring boot starter,以自动配置,快速启动
26 |
27 | # API使用
28 | Iris核心代码不依赖Spring,可脱离Spring使用。
29 | 1. 启动etcd注册中心
30 | 2. 编写一个接口IHelloService
31 | ```java
32 | public interface IHelloService {
33 | String hello(String name);
34 | }
35 | ```
36 | 3. 编写一个IHelloService的实现
37 | ```java
38 | public class HelloService implements IHelloService {
39 | @Override
40 | public String hello(String name){
41 | return "Hello, " + name;
42 | }
43 | }
44 | ```
45 | 4. 启动Server
46 | ```java
47 | IRegistry registry = new EtcdRegistry("http://127.0.0.1:2379");
48 | RpcServer server = new RpcServer(registry)
49 | .port(2017)
50 | .exposeService(IHelloService.class,new HelloService());
51 | server.run();
52 | ```
53 | 5. 启动client
54 | ```java
55 | RpcClient client = new RpcClient(registry);
56 | IHelloService helloService = client.create(IHelloService.class);
57 | String s = helloService.hello("leo");
58 | System.out.println(s); // hello, leo
59 | ```
60 | 6. 停止server
61 | ```text
62 | 因为服务没有provider,client报错找不到provider
63 | ```
64 | 7. 启动server
65 | ```text
66 | server启动后,会去etcd注册中心注册服务,client端马上正常工作。
67 | ```
68 |
69 | # Spring配置
70 | 服务提供者,使用自定义注解@Service来暴露服务,通过interfaceClass来指定服务的接口。
71 | 该@Service注解是iris提供的,并非Spring的注解
72 | ```java
73 | @Service(interfaceClass = IHelloService.class)
74 | public class HelloService implements IHelloService {
75 | @Override
76 | public String hello(String name) throws Exception {
77 | return "hello" + name;
78 | }
79 | }
80 | ```
81 | 服务使用者,通过@Reference来引用远程服务,就像使用本地的SpringBean一样。背后的SpringBean封装和Rpc调用对开发者透明。使用体验和Dubbo是一样的。
82 | ```java
83 | public class Baz {
84 |
85 | @Reference(interfaceClass = IHelloService.class)
86 | private IHelloService helloService;
87 |
88 | public void hello(String name) throws Exception {
89 | System.out.println(helloService.hello(name));
90 | }
91 | }
92 |
93 | ```
94 | 配置服务提供者,本例子使用XML配置,使用Java Code配置也可以。
95 | ```xml
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | ```
108 | 配置服务消费者,本例子使用XML配置,使用Java Code配置也可以。
109 | ```xml
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | ```
122 |
123 | # Spring Boot配置
124 | 使用原生的Spring配置还是有些繁琐,可以使用Spring Boot来获得更好的开发体验。
125 | 服务提供者
126 | ```java
127 | @Service(interfaceClass = IHelloService.class)
128 | public class HelloService implements IHelloService {
129 | @Override
130 | public String hello(String name) throws Exception {
131 | return "Hello, " + name + ", from com.leibangzhu.iris.springboot.HelloService";
132 | }
133 | }
134 | ```
135 | 服务消费者
136 | ```java
137 | @Component
138 | public class Foo {
139 |
140 | @Reference(interfaceClass = IHelloService.class)
141 | private IHelloService helloService;
142 |
143 | public String hello(String name) throws Exception {
144 | return helloService.hello(name);
145 | }
146 | }
147 | ```
148 | 在application.properties文件中配置服务提供者
149 | ```properties
150 | iris.registry.address=http://127.0.0.1:2379
151 |
152 | iris.server.enable=true
153 | iris.server.port=2017
154 | iris.annotation.package=com.leibangzhu.iris.springboot
155 | ```
156 | 在application.properties文件中配置服务消费者
157 | ```properties
158 | iris.registry.address=http://127.0.0.1:2379
159 |
160 | iris.client.enable=true
161 | ```
162 | 使用SpringBoot时,不许再手动配置相关的spring bean,Iris提供的spring boot starter会自动配置好这些spring bean。
163 |
164 | # Iris的微内核加插件机制
165 | * Iris使用了SPI机制,实现了微内核加插件的架构。
166 | * Iris里的许多功能都是以插件的形式加载的。一个功能点就是一个扩展点,就是一个接口。通过注入的方式,将某个实现注入到Iris中。
167 | * 扩展点的加载没有使用第三方的容器,比如Spring,而是自己实现了一个轻量级的容器。对Java的SPI机制进行了一下扩展和加强。
168 | * 每个扩展点会有多个实现,开发者可以自己配置使用哪个,比如使用zookeeper注册中心或etcd注册中心。
169 | * Iris内置的扩展实现满足大部分要求,开发者也可以自己编写扩展点的实现,加载到Iris中。
170 | * Iris会扫描classpath下面的`/META/extensions`文件夹中的文件,读取扩展点信息,然后运行时动态加载。
171 | * 使用时通过ExtensionLoader加载对应的插件
172 | * ExtensionLoader支持类似于Spring的IoC和AoP功能。即,扩展点中可以自动装配其他的扩展点。Iris提供Wrapper使用Decrator模式来实现AOP。
173 | * 所有的扩展点元数据文件都在`/META-INF/extensions`文件夹下,文件名是实现的扩展点的接口的全类名。
174 | * 文件的内容是key=value的形式。key是扩展点实现的name,value是实现类的全类名。实现类是一个简单的Java类,不依赖任何第三方接口和注解。
175 | * 使用Wrapper实现AOP时,在扩展点name前加上`+`。比如:`+logWrapper=com.leibangzhu.iris.core.SomeExtension`
176 |
177 | ### 一个负载均衡器的Demo
178 | Iris中的服务提供者有多个,client端调用的时候,有一个负载均衡的策略。
179 | Iris目前提供了1个实现:随机选择一个提供者。以后会提供更多的负载均衡策略。如果有多个,只需要在iris.properties或application.properties中添加配置:
180 | ```properties
181 | iris.loadbalance=random
182 | ```
183 | Iris提供的的`ILoadBalance`接口。
184 | ```java
185 | @Extension(defaultValue = "random")
186 | public interface ILoadBalance {
187 | int select(@Adaptive("loadbalance")Map config,int amount) throws Exception;
188 | }
189 | ```
190 | * @Extension注解声明这是一个扩展点
191 | * defaultValue表示默认使用random这个扩展点实现
192 | * @Adaptive注解声明这是一个自适应扩展方法,会根据运行时信息动态选择对应的扩展点实现。类似于一个动态代理。
193 | 自带的随机的负载均衡是在下面的文件中定义的:
194 | `/src/main/resources/META-INF/extensions/com.leibangzhu.iris.core.loadbalance.ILoadBalance`文件的内容:
195 | ```text
196 | random=com.leibangzhu.iris.core.loadbalance.RandomLoadBalance
197 | ```
198 | 通过ExtensionLoader获取扩展点:
199 | ```java
200 | ILoadBalance loadBalance = ExtensionLoader.getExtensionLoader(ILoadBalance.class).getAdaptiveInstance();
201 | // get runtime configuration and load config to map
202 | // get actual loadbalance from iris.properties or application.properties file
203 | String loadbalance = IrisConfig.getLoadbalance();
204 | map.put("loadbalance",loadbalance)
205 | loadBalance.select(map,size);
206 | ```
207 |
208 | ### 扩展自己的负载均衡器
209 | 开发者想使用轮询的负载均衡策略,可以按照以下步骤来扩展:
210 | 1. 编写一个类,实现ILoadBalance接口
211 | ```java
212 | public class RoundRobinLoadBalance implements ILoadBalance {
213 | @Override
214 | public int select(Map config, int amount) throws Exception {
215 | // put your code here ...
216 | }
217 | }
218 | ```
219 | 2. 在classpath中添加一个文件:
220 | `/META-INF/extensions/com.leibangzhu.iris.core.loadbalande.ILoadBalance`
221 | ```properties
222 | roundrobin=com.mycompany.foo.bar.RoundRobinLoadBalance
223 | ```
224 | 3. 在`iris.properties`或`application.properties`中添加配置:
225 | ```properties
226 | iris.loadbalance=roundrobin
227 | ```
228 | 这样,Iris就会使用我们自定义的轮询负载均衡了。
229 |
230 | # Why iris
231 | `iris`取名于梵高的画**鸢尾花**
232 |
--------------------------------------------------------------------------------
/iris/.gitignore:
--------------------------------------------------------------------------------
1 | iris-client/target
2 | iris-core/target
3 | iris-spring/target
4 | iris-spring-boot/target
5 | iris-protocol/target
6 | iris-registry/target
7 | iris-server/target
8 | .flattened-pom.xml
9 |
--------------------------------------------------------------------------------
/iris/README.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iris/iris-bom/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | iris
7 | com.leiwei2094
8 | ${revision}
9 |
10 | 4.0.0
11 |
12 | iris-bom
13 | pom
14 |
15 |
16 | 0.0.1
17 | 4.12
18 | 4.1.12.Final
19 | 1.7.9
20 | 1.5.2
21 | 2.6
22 | 0.0.1-SNAPSHOT
23 | 4.3.13.RELEASE
24 | 1.5.9.RELEASE
25 |
26 |
27 |
28 |
29 |
30 | com.coreos
31 | jetcd-core
32 | ${etcd.version}
33 |
34 |
35 | io.netty
36 | netty-codec-http2
37 |
38 |
39 | io.netty
40 | netty-handler-proxy
41 |
42 |
43 |
44 |
45 | junit
46 | junit
47 | ${junit.version}
48 | test
49 |
50 |
51 | io.netty
52 | netty-all
53 | ${netty.version}
54 |
55 |
56 | net.bytebuddy
57 | byte-buddy
58 | ${byte-buddy.version}
59 |
60 |
61 | io.protostuff
62 | protostuff-core
63 | ${protostuff.version}
64 |
65 |
66 | io.protostuff
67 | protostuff-runtime
68 | ${protostuff.version}
69 |
70 |
71 | org.objenesis
72 | objenesis
73 | ${objenesis.version}
74 |
75 |
76 | com.leiwei2094
77 | coco
78 | ${com.leiwei2094.coco.version}
79 |
80 |
81 | org.springframework
82 | spring-context
83 | ${spring.version}
84 |
85 |
86 | org.springframework.boot
87 | spring-boot-starter
88 | ${springboot.version}
89 |
90 |
91 | org.slf4j
92 | slf4j-api
93 |
94 |
95 |
96 |
97 | org.springframework.boot
98 | spring-boot-configuration-processor
99 | ${springboot.version}
100 | true
101 |
102 |
103 | org.springframework.boot
104 | spring-boot-starter-test
105 | ${springboot.version}
106 |
107 |
108 | org.slf4j
109 | slf4j-api
110 |
111 |
112 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/iris/iris-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | iris-parent
7 | com.leiwei2094
8 | ${revision}
9 | ../iris-parent/pom.xml
10 |
11 | 4.0.0
12 |
13 | iris-client
14 |
15 |
16 |
17 | com.leiwei2094
18 | iris-registry
19 | ${project.version}
20 |
21 |
22 | com.leiwei2094
23 | iris-protocol
24 | ${project.version}
25 |
26 |
27 | net.bytebuddy
28 | byte-buddy
29 |
30 |
31 | junit
32 | junit
33 |
34 |
35 | junit
36 | junit
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/ConnectManager.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import com.leiwei2094.coco.ExtensionLoader;
4 | import com.leiwei2094.iris.core.Endpoint;
5 | import com.leiwei2094.iris.core.IrisConfig;
6 | import com.leiwei2094.iris.core.loadbalance.ILoadBalance;
7 | import com.leiwei2094.iris.registry.IEventCallback;
8 | import com.leiwei2094.iris.registry.IRegistry;
9 | import com.leiwei2094.iris.registry.RegistryEvent;
10 | import io.netty.bootstrap.Bootstrap;
11 | import io.netty.channel.Channel;
12 | import io.netty.channel.EventLoopGroup;
13 | import io.netty.channel.nio.NioEventLoopGroup;
14 | import io.netty.channel.socket.nio.NioSocketChannel;
15 |
16 | import java.util.*;
17 |
18 | public class ConnectManager implements IConnectManager, IEventCallback {
19 |
20 | private IRegistry registry;
21 | private EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
22 | private Map> channelsByService = new LinkedHashMap<>();
23 |
24 | public ConnectManager(IRegistry registry) {
25 | this.registry = registry;
26 | this.registry.watch(this);
27 | }
28 |
29 | @Override
30 | public Channel getChannel(String serviceName) throws Exception {
31 | if (!channelsByService.containsKey(serviceName)) {
32 | List endpoints = registry.find(serviceName);
33 | List channels = new ArrayList<>();
34 | for (Endpoint endpoint : endpoints) {
35 | channels.add(connect(endpoint.getHost(), endpoint.getPort()));
36 | }
37 | channelsByService.put(serviceName, channels);
38 | }
39 |
40 | // select one channel from all available channels
41 | int size = channelsByService.get(serviceName).size();
42 | ILoadBalance loadBalance = ExtensionLoader.getExtensionLoader(ILoadBalance.class).getAdaptiveInstance();
43 | if (0 == size) {
44 | System.out.println("NO available providers for service: " + serviceName);
45 | }
46 |
47 | String loadbalance = IrisConfig.get("iris.loadbalance");
48 | Map map = new LinkedHashMap<>();
49 | map.put("loadbalance", loadbalance);
50 | int index = loadBalance.select(map, size);
51 | ChannelWrapper channelWrapper = channelsByService.get(serviceName).get(index);
52 | System.out.println("Load balance:" + loadbalance + "; Selected endpoint: " + channelWrapper.toString());
53 | return channelWrapper.getChannel();
54 | }
55 |
56 | private ChannelWrapper connect(String host, int port) throws Exception {
57 |
58 | Bootstrap b = new Bootstrap()
59 | .group(eventLoopGroup)
60 | .channel(NioSocketChannel.class)
61 | .handler(new RpcClientInitializer());
62 |
63 | Channel channel = b.connect(host, port).sync().channel();
64 | ChannelWrapper channelWrapper = new ChannelWrapper(new Endpoint(host, port), channel);
65 | return channelWrapper;
66 | }
67 |
68 | @Override
69 | public void execute(RegistryEvent event) {
70 | if (event.getEventType() == RegistryEvent.EventType.DELETE) {
71 |
72 | // key: /iris/com.leiwei2094.iris.bytebuddy.IHelloService/192.168.41.215:2017
73 |
74 | String s = event.getKeyValue().getKey();
75 | String serviceName = s.split("/")[2]; // com.leiwei2094.iris.bytebuddy.IHelloService
76 | String endpointStr = s.split("/")[3];
77 |
78 | String host = endpointStr.split(":")[0]; // 192.168.41.215
79 | int port = Integer.valueOf(endpointStr.split(":")[1]); // 2017
80 |
81 | Iterator iterator = channelsByService.get(serviceName).iterator();
82 | while (iterator.hasNext()) {
83 | Endpoint endpoint = iterator.next().getEndpoint();
84 | if (endpoint.getHost().equals(host) && (endpoint.getPort() == port)) {
85 | iterator.remove();
86 | }
87 | }
88 | }
89 |
90 | if (event.getEventType() == RegistryEvent.EventType.PUT) {
91 |
92 | // key: /iris/com.leiwei2094.iris.bytebuddy.IHelloService/192.168.41.215:2017
93 |
94 | String s = event.getKeyValue().getKey();
95 | String serviceName = s.split("/")[2]; // com.leiwei2094.iris.bytebuddy.IHelloService
96 | String endpointStr = s.split("/")[3];
97 |
98 | String host = endpointStr.split(":")[0]; // 192.168.41.215
99 | int port = Integer.valueOf(endpointStr.split(":")[1]); // 2017
100 |
101 | try {
102 | channelsByService.get(serviceName).add(connect(host, port));
103 | } catch (Exception e) {
104 | e.printStackTrace();
105 | }
106 | }
107 | }
108 |
109 | private static class ChannelWrapper {
110 | private Endpoint endpoint;
111 | private Channel channel;
112 |
113 | public ChannelWrapper(Endpoint endpoint, Channel channel) {
114 | this.endpoint = endpoint;
115 | this.channel = channel;
116 | }
117 |
118 | public Endpoint getEndpoint() {
119 | return endpoint;
120 | }
121 |
122 | public Channel getChannel() {
123 | return channel;
124 | }
125 |
126 | @Override
127 | public String toString() {
128 | return endpoint.getHost() + ":" + endpoint.getPort();
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/IConnectManager.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import io.netty.channel.Channel;
4 |
5 | public interface IConnectManager {
6 | Channel getChannel(String serviceName) throws Exception;
7 | }
8 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/IRpcClient.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | public interface IRpcClient {
4 |
5 | T create(Class clazz) throws Exception;
6 | }
7 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/RpcClient.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import com.leiwei2094.iris.registry.IRegistry;
4 | import net.bytebuddy.ByteBuddy;
5 | import net.bytebuddy.implementation.MethodDelegation;
6 |
7 | import java.util.LinkedHashMap;
8 | import java.util.Map;
9 |
10 | import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
11 |
12 | public class RpcClient implements IRpcClient {
13 |
14 | ConnectManager connectManager;
15 | private IRegistry registry;
16 | private Map proxyByClass = new LinkedHashMap<>();
17 |
18 | public RpcClient(IRegistry registry) {
19 | this.registry = registry;
20 | this.connectManager = new ConnectManager(registry);
21 | //this.registry.watch();
22 | }
23 |
24 | @Override
25 | public T create(Class clazz) throws Exception {
26 | if (!proxyByClass.containsKey(clazz.getName())) {
27 | T proxy = new ByteBuddy()
28 | .subclass(clazz)
29 | .method(isDeclaredBy(clazz)).intercept(MethodDelegation.to(new RpcInvokeInterceptor(connectManager)))
30 | .make()
31 | .load(getClass().getClassLoader())
32 | .getLoaded()
33 | .newInstance();
34 |
35 | proxyByClass.put(clazz.getName(), proxy);
36 | }
37 |
38 | return (T)proxyByClass.get(clazz.getName());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/RpcClientHandler.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import com.leiwei2094.iris.protocol.RpcResponse;
4 | import io.netty.channel.ChannelHandlerContext;
5 | import io.netty.channel.SimpleChannelInboundHandler;
6 |
7 | public class RpcClientHandler extends SimpleChannelInboundHandler {
8 |
9 | @Override
10 | protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcResponse response) throws Exception {
11 | String requestId = response.getRequestId();
12 | RpcFuture future = RpcRequestHolder.get(requestId);
13 | if (null != future) {
14 | RpcRequestHolder.remove(requestId);
15 | future.done(response);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/RpcClientInitializer.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import com.leiwei2094.iris.protocol.RpcDecoder;
4 | import com.leiwei2094.iris.protocol.RpcEncoder;
5 | import com.leiwei2094.iris.protocol.RpcRequest;
6 | import com.leiwei2094.iris.protocol.RpcResponse;
7 | import io.netty.channel.ChannelInitializer;
8 | import io.netty.channel.ChannelPipeline;
9 | import io.netty.channel.socket.SocketChannel;
10 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
11 |
12 | public class RpcClientInitializer extends ChannelInitializer {
13 | @Override
14 | protected void initChannel(SocketChannel socketChannel) throws Exception {
15 | ChannelPipeline pipeline = socketChannel.pipeline();
16 | pipeline.addLast(new RpcEncoder(RpcRequest.class));
17 | pipeline.addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 0));
18 | pipeline.addLast(new RpcDecoder(RpcResponse.class));
19 | pipeline.addLast(new RpcClientHandler());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iris/iris-client/src/main/java/com/leiwei2094/iris/client/RpcFuture.java:
--------------------------------------------------------------------------------
1 | package com.leiwei2094.iris.client;
2 |
3 | import com.leiwei2094.iris.protocol.RpcResponse;
4 |
5 | import java.util.concurrent.*;
6 |
7 | public class RpcFuture implements Future