博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
简单的服务调用框架实现
阅读量:6830 次
发布时间:2019-06-26

本文共 3832 字,大约阅读时间需要 12 分钟。

hot3.png

断断续续用了几天时间,写了一个简单的粗糙的类似DUBBO的服务调用框架。

我给框架起了个很山寨的名字,暂且命名为:pangu,中文是盘古。该名称意为开天辟地,这里表示为连接客户端和服务端的桥梁,开源在 。

目前该框架的实现还属于toy级别的,主要表现为以下几个方面:

  • 有些类,方法命名还不是很考究,类的职责有待进一步明确;存在一部分硬编码。
  • 没有注册中心,服务依赖关系统计等。
  • 没有拦截器,没有事件,没有javassist,传输协议和数据协议接口没有抽象,负载均衡,失败重试,等等。

本文主要记录一下该框架中的几个关键知识点,供有兴趣的人参考。

Using Spring extension

Custom XML tag

详细介绍 ,在本文中的实现请参考META-INF里面的文件以及CustomNamespaceHandler等核心几个类。

核心实现如下:

public BeanDefinition parse(Element element, ParserContext parserContext) {RootBeanDefinition beanDefinition = new RootBeanDefinition();beanDefinition.setBeanClass(beanClass);beanDefinition.setLazyInit(false);if (ConsumerConfig.class.equals(beanClass)) {    String id = element.getAttribute("id");    String interfaceName = element.getAttribute("interface");    beanDefinition.getPropertyValues().addPropertyValue("id", id);    beanDefinition.getPropertyValues().addPropertyValue(	    "interfaceName", interfaceName);    parserContext.getRegistry().registerBeanDefinition(id,	    beanDefinition);} else if (ProviderConfig.class.equals(beanClass)) {    String ref = element.getAttribute("ref");    Object reference = new RuntimeBeanReference(ref);    beanDefinition.getPropertyValues().addPropertyValue("ref",	    reference);    String interfaceName = element.getAttribute("interface");    beanDefinition.getPropertyValues().addPropertyValue(	    "interfaceName", interfaceName);    parserContext.getRegistry().registerBeanDefinition(interfaceName,	    beanDefinition);}return beanDefinition;}

RuntimeBeanReference

在上面的代码片段中,出现了这个类:RuntimeBeanReference。这个的类的主要作用是根据bean名称返回bean实例的引用,避免客户端显式获取bean实例。

FactoryBean & Dynamic Proxy

在客户端获取一个bean时,其实这个bean是个代理类。在真正进行客户端调用时,会通过动态代理机制将数据请求发送到远端服务器上面。

在本实现中,由于ConsumerConfig实现了FactoryBean接口,那么当客户端根据这个beanId获取bean实例后,Spring会自动调用该bean的getObject()方法。究其Spring的FactoryBean接口调用实现时,也是直接instanceof判断了下。

public Object ConsumerConfig.getObject() throws Exception {ClassLoader clazzLoader = Thread.currentThread()	.getContextClassLoader();Class
intefaceClazz = null;try { intefaceClazz = Class.forName(interfaceName, false, clazzLoader);} catch (ClassNotFoundException e) { throw new PanguRuntimeException(e);}// TODO add cache and get channel by configNetworkClient channel = new NettyClient();ConsumerInvocationHandler invocationHandler = new ConsumerInvocationHandler( channel, this);Class
[] intefaceClazzArray = new Class[] { intefaceClazz };Object consumerProxy = Proxy.newProxyInstance(clazzLoader, intefaceClazzArray, invocationHandler);return consumerProxy;}

关于动态代理,可以见上面方法的实现。JDK动态代理实现原理见笔者的这篇介绍:

Netty

Serialization

在对象序列化时,简单使用了netty自带的ObjectEncoderObjectDecoder

代码片段如下:

public void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new ObjectEncoder(),	new ObjectDecoder(ClassResolvers.cacheDisabled(null)));pipeline.addLast("handler", CLIENT_HANDLER);}

FutureResponse

在本文中,当客户端调用一个服务时,需要同步等待服务端的响应。而由于Netty是一个异步调用框架,一般情况下无法直接实现这种类似功能。

在参考Dubbo的实现后,使用了类似的机制。FutureResponse的代码片段如下:

public Response get() {lock.lock();try {    // TODO add timeout    while (!isDone()) {	done.await();    }} catch (InterruptedException e) {    throw new RuntimeException(e);} finally {    lock.unlock();}return response;}public static void doSingalWhenReceivedServerResponse(Response response) {FutureResponse future = futures.remove(response.getId());if (future != null) {    future.assginResponseAndDoSignal(response);}}private boolean isDone() {return this.response != null;}private void assginResponseAndDoSignal(Response response) {lock.lock();try {    this.response = response;    done.signal();} finally {    lock.unlock();}}

How To Run

目前这个简单的服务调用框架开源在github上,地址是

在执行前,可能需要把buildPath改一下,使配置文件都编译到classPath下面;不然会报Spring配置文件找不到或者XML解析错误。

在执行时,依次运行EchoServerTestEchoClientTest即可。

Have Fun。

Reference

转载于:https://my.oschina.net/geecoodeer/blog/208859

你可能感兴趣的文章
关于LR中的EXTRARES
查看>>
转:如何转换Android打包用jks格式keystore证书为Air用pkcs12格式p12证书
查看>>
光伏发电系列:关于光伏发电站的建设成本和资金回收周期
查看>>
Linux内核源代码目录树结构
查看>>
js常用正则表达式
查看>>
jQuery-1.9.1源码分析系列(七) 钩子(hooks)机制及浏览器兼容续
查看>>
数据仓库专题18-数据建模语言IDEF(转载)
查看>>
GridView自带分页 1总页数 首页 下一页 上一页 尾页 X 页 go 实现方法 .
查看>>
Caffe学习系列(9):运行caffe自带的两个简单例子
查看>>
android:EditText控件
查看>>
十种JAVA排序算法实例
查看>>
QQ空间开放平台开发教程-SDK和API的使用
查看>>
如何使用 SPICE client (virt-viewer) 来连接远程虚拟机桌面?
查看>>
mysql sql_safe_updates 分析
查看>>
Matlab与C++混合编程 编写独立外部应用程序时出现“无法定位序数3906于动态链接库LIBEAY32.dll上”错误...
查看>>
SQL Server 函数的使用 Function
查看>>
Mozilla Brick:一个Web组件Polyfill库
查看>>
C++中出现的计算机术语1
查看>>
P - A + B(第二季水)
查看>>
Atitit. 真正的全中国文字attilax易语言的特点以及范例
查看>>