RPC框架Pigeon
Pigeon的由来
之前就有使用过相关RPC的框架,如dubbo,就想象着它是如何来实现的,能让直接调用类的方法就能实现远程调用然后获取结果啥的,看着dubbo的架构图:
看着挺简单的,就一个注册中心,然后提供者注册上去,消费者去寻找相关的提供者然后进行通信,提供者再调用实现类的方法来执行获取结果返回给消费者。
然后之前也简略的看过netty的源码,但是自己没有实际的应用场景,就想着来写一个简单的rpc就实现,也能够实践一下netty.
rpc通信方式之前就有想法怎么来实现,但是没场景就没写的,然后看到了seata通信的时候,和我之前的想法是差不多一致的,但是实现的话肯定我就弱爆了,这个rpc也借鉴了seata的相关实现。
写Pigeon遇到的一些问题
因为该rpc就使用了一天的时间来完成,然后混了太久的crud,好多知识点也不太熟练了,遇到了大大小小的问题。
刚开始遇到的就是提供者应该注册什么样的数据到注册上去,是以接口为粒度,还是以服务为粒度,以服务为粒度的话,还要注册接口与服务的映射关系,就没这么选择了,最后选的是以接口为粒度。
然后这个服务的元数据是什么呢,比如ip port什么的,因为只是简单的写一个,就没弄那么麻烦,直接就是ip:port了;
然后就是注册中心,选型有很多,比如zookeeper,nacos.. ,该怎么抽象出来,能够更好的扩展,目前只写了zookeeper的实现。
然后就是通信的一些问题了,协议怎么搞,怎么编码节码,是使用json序列话呢,还是java序列话呢。
最后整合spring的时候也遇见了一些小插曲,不过以很笨的方式解决了.
具体代码实现
Pigeon类就是屏蔽相关实现,只需要提供一个config就能启动。
public class Pigeon {
private PigeonConfig pigeonConfig;
private ServiceRegistry serviceRegistry;
private RemotingClinet remotingClinet;
private RemotingServer remotingServer;
protected PigeonConfig getPigeonConfig() {
return pigeonConfig;
}
protected ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
protected RemotingClinet getRemotingClinet() {
return remotingClinet;
}
protected RemotingServer getRemotingServer() {
return remotingServer;
}
public Pigeon(PigeonConfig pigeonConfig) {
this.pigeonConfig = pigeonConfig;
}
public void start() {
Map<Service, Object> serviceObjectMap = searchPigeon();
startRegistry(serviceObjectMap.keySet());
startRemoting(serviceObjectMap);
}
protected void startRemoting(Map<Service, Object> serviceObjectMap) {
remotingClinet = new RemotingClinet();
remotingServer = new RemotingServer(pigeonConfig.getPort(), serviceObjectMap);
remotingServer.start();
}
protected void startRegistry(Set<Service> serviceList) {
serviceRegistry = new ZookeeperServiceRegistry(pigeonConfig.getPort(), pigeonConfig.getRegistry());
serviceRegistry.addAllService(serviceList);
serviceRegistry.start();
}
protected Map<Service, Object> searchPigeon() {
Map<Service, Object> serviceHandlerMap = new HashMap<>();
String[] scanPackages = pigeonConfig.getPackages();
Set<Class<?>> classes = ClassUtil.getClasses(scanPackages);
classes
.stream()
.filter(cl -> !cl.isInterface() && cl.isAnnotationPresent(PigeonService.class))
.forEach(cl -> {
PigeonService annotation = cl.getAnnotation(PigeonService.class);
String group = annotation.group();
String version = annotation.version();
Object handler;
try {
handler = serviceHandler(cl);
} catch (Exception e) {
e.printStackTrace();
return;
}
if (handler == null) return;
Class<?>[] interfaces = cl.getInterfaces();
for (Class<?> anInterface : interfaces) {
if (!(anInterface.equals(Object.class) || anInterface.equals(Serializable.class))) {
Service service = new Service(anInterface.getName(), group, version);
ServiceHandler serviceHandler = new ServiceHandler();
serviceHandler.setService(service);
serviceHandler.setHandler(handler);
serviceHandlerMap.put(service, handler);
}
}
});
return serviceHandlerMap;
}
protected Object serviceHandler(Class<?> cl) throws InstantiationException, IllegalAccessException {
return cl.newInstance();
}
public <T> T getProxy(Class<T> clazz) {
return getProxy(clazz, "default", "default");
}
public <T> T getProxy(Class<T> clazz, String group, String version) {
Service service = new Service(clazz.getName(), group, version);
return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{clazz}, new ServiceProxy(service, serviceRegistry, remotingClinet));
}
}
复制代码
代码也有好几十个类,就不贴了,
点击跳转github仓库
具体演示
先启动一个zookeeper,目前只支持这个。。
在example模块中有个helloworld模块,如果zk是在本地且端口是默认的话那么久可以直接进行demo演示,不是的话就修改一下配置即可.
提供了基础demo和spring boot整合的demo。
结束语
小伙伴有什么建议可添加下方的联系方式。
QQ: 1448983340
微信: 18390010937