dubbo源代码阅读

一,自定义的spring配置

基于sping扩展schma利用DubboNamespaceHandler实现对自定义schema的解析。见配置文件:spring.handlersspring.schemas

二,Consumer对于服务接口的透明调用

基于Javassist的动态代理模式,自动生成代理类。

通过InvokerInvocationHandler的invoker调用:

returninvoker.invoke(newRpcInvocation(method,args)).recreate();

invokerRPC通信,基于mina、netty等。

三,dubbo扩展机制

实现方式类似sun的spi模式,实现自身的可扩展性。简单实现了接口的注入。

1,Extension注解value=组件的名字

具体实现见ExtensionLoader

2,主要方法:

loadExtensionClasses加载所有实现了META-INF/services目录下文件中的类,文件名为接口名。根据Extension注解的名字为key,CLASS为VALUE放到缓存的MAP中。

getAdaptiveExtension利用代码生成创建一下接口的适配器类:

Protocol

Cluster

ProxyFactory

等等

这个适配器类以Adaptive注解声明的值或者接口名为KEY,从URL中的参数或者URLgetProtocol()作为key的值,

然后ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(key)获得相应的实例。

getExtension(STR)方法获得接口实例,第一次取时创建,并按顺序实例化包装类,并把最后一个包装类返回。

Class<?>clazz=getExtensionClasses().get(name);

if(clazz==null){

thrownewIllegalStateException("Nosuchextension"+type.getName()+"byname"+name);

}

try{

//实例化并自动注入一些接口的适配器

Tinstance=injectExtension((T)clazz.newInstance());

Set<Class<?>>wrapperClasses=cachedWrapperClasses;

if(wrapperClasses!=null&&wrapperClasses.size()>0){

for(Class<?>wrapperClass:wrapperClasses){

instance=injectExtension((T)wrapperClass.getConstructor(type).newInstance(instance));

//injectExtension实例化包装类,并注入接口的适配器,注意这个地方返回的是最后一个包装类。

}

}

returninstance;

}catch(Throwablet){

thrownewIllegalStateException("Extensioninstance(name:"+name+",class:"+

type+")couldnotbeinstantiated:"+t.getMessage(),t);

}

比如获得Protocol接口的实例privatestaticfinalProtocolprotocol=ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();过程如下:

ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()利用javassist动态生成一个Protocol$Adaptive的实例,

生成的class反编译后代码如下:

//消费者调用这个方法获得Invoker

publicInvokerrefer(ClassparamClass,URLparamURL)

throwsRpcException

{

if(paramURL==null)

thrownewIllegalArgumentException("url==null");

URLlocalURL=paramURL;

//默认的协议dubbo

Stringstr=(localURL.getProtocol()==null)?"dubbo":localURL.getProtocol();

if(str==null)

thrownewIllegalStateException("Failtogetextension(com.alibaba.dubbo.rpc.Protocol)namefromurl("+localURL.toString()+")usekeys([protocol])");

/*注意这个地方获得的Protocol实例是:

*com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper包装类。主要是为了实现

*对invoker的包装。

*com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper->

*com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper->

*com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol

*层层包装创建ListenerInvokerWrapper,实现InvokerListener调用;创建InvokerChain实现Filter的调用。

*默认的客户端过滤链"consumercontext","compatible","deprecated","collect","genericimpl","activelimit","monitor","future"

*见com.alibaba.dubbo.rpc.RpcConstants.DEFAULT_REFERENCE_FILTERS

*/

ProtocollocalProtocol=(Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(str);

returnlocalProtocol.refer(paramClass,paramURL);

}

//服务提供者调用这个方法,发布服务。

publicExporterexport(InvokerparamInvoker)

throwsRpcException

{

if(paramInvoker==null)

thrownewIllegalArgumentException("com.alibaba.dubbo.rpc.Invokerargument==null");

if(paramInvoker.getUrl()==null)

thrownewIllegalArgumentException("com.alibaba.dubbo.rpc.InvokerargumentgetUrl()==null");

URLlocalURL=paramInvoker.getUrl();

Stringstr=(localURL.getProtocol()==null)?"dubbo":localURL.getProtocol();

if(str==null)

thrownewIllegalStateException("Failtogetextension(com.alibaba.dubbo.rpc.Protocol)namefromurl("+localURL.toString()+")usekeys([protocol])");

/*这个地方获得的Protocol实例同样是

*com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper包装类,实现对于对

*invoker的包装

*加载的服务端过滤链,默认是"context","token","exception","echo","generic","accesslog","trace","classloader","executelimit","monitor","timeout"

*见com.alibaba.dubbo.rpc.RpcConstants.DEFAULT_SERVICE_FILTERS

*/

ProtocollocalProtocol=(Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(str);

returnlocalProtocol.export(paramInvoker);

}

之所以默认获得的Protocol实例是com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper,因为在配置文件中

META-INF/services/com.alibaba.dubbo.rpc.Protocol文件内容如下:

com.alibaba.dubbo.registry.support.RegistryProtocol

com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper

com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper--最后一个包装类

com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol

com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol

com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol

com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

四,Wrapper帮助类

提高调用某一个类的某一个方法的性能(避免反射调用)

使用javassist动态生成一个Wrapper的子类,实现抽象方法invokeMethod,

/**

*invokemethod.

*

*@paraminstanceinstance.

*@parammnmethodname.

*@paramtypes

*@paramargsargumentarray.

*@returnreturnvalue.

*/

abstractpublicObjectinvokeMethod(Objectinstance,Stringmn,Class<?>[]types,Object[]args)throwsNoSuchMethodException,InvocationTargetException;

生成的class的代码类似

publicObjectinvokeMethod(ObjectparamObject,StringparamString,Class[]paramArrayOfClass,Object[]paramArrayOfObject)

throwsInvocationTargetException

{

RegistryServicelocalRegistryService;

try

{

localRegistryService=(RegistryService)paramObject;

}

catch(ThrowablelocalThrowable1)

{

thrownewIllegalArgumentException(localThrowable1);

}

try

{

if("register".equals(paramString))

{

localRegistryService.register((URL)paramArrayOfObject[0]);

returnnull;

}

if("subscribe".equals(paramString))

{

localRegistryService.subscribe((URL)paramArrayOfObject[0],(NotifyListener)paramArrayOfObject[1]);

returnnull;

}

if("unregister".equals(paramString))

{

localRegistryService.unregister((URL)paramArrayOfObject[0]);

returnnull;

}

if("unsubscribe".equals(paramString))

{

localRegistryService.unsubscribe((URL)paramArrayOfObject[0],(NotifyListener)paramArrayOfObject[1]);

returnnull;

}

}

catch(ThrowablelocalThrowable2)

{

thrownewInvocationTargetException(localThrowable2);

}

thrownewNoSuchMethodException("Notfoundmethod\""+paramString+"\"inclasscom.alibaba.dubbo.registry.RegistryService.");

}

直接动态生成了一个子类,没有通过反射调用。

Consumer服务消费方分析

以dubbo-demo-simple-consumer的源码为分析的起点,解析Consumer的运行流程。

1,配置文件的解析

<!--引用远程服务配置-->

<dubbo:referenceid="demoService"interface="com.alibaba.dubbo.demo.DemoService"/>

首先dubbo基于spring的schma扩展机制实现了自定义的命名空间定义和配置的解析。

源码见:com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser

registerBeanDefinitionParser("reference",newDubboBeanDefinitionParser(ReferenceBean.class,false));

DubboBeanDefinitionParser和ReferenceBean实现对dubbo:reference的解析。

2,获得服务代理

在DemoServicedemoService=(DemoService)context.getBean("demoService");时ReferenceBean作为FactoryBean实现DemoService接口的代理对象的创建,见源码:

com.alibaba.dubbo.config.spring.ReferenceBean.getObject()
com.alibaba.dubbo.config.ReferenceConfig.get()
com.alibaba.dubbo.config.ReferenceConfig.init()

ReferenceConfig.java:

获得protocol,cluster,proxyFactory接口的实例,实际调用如下:

protocol--》Protocol$Adaptive-》com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper--

cluster--》com.alibaba.dubbo.rpc.cluster.support.FailoverCluster

proxyFactory--》com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory

createProxy方法解析:

I,获得URL,从dubbo:reference,url属性或者从loadRegistries();通过注册中心配置拼装URL。设置URL的protocol为Constants.REGISTRY_PROTOCOLregistry

II,获得invoker=protocol.refer(interfaceClass,urls.get(0));

Protocol$Adaptive-->根据URL的协议获得com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper->com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper-->com.alibaba.dubbo.registry.support.RegistryProtocol

refer(interfaceClass,urls.get(0))->com.alibaba.dubbo.registry.support.RegistryProtocol.refer->

1,RegistryFactory--getRegistryRegistryFactory根据url配置可能是DubboRegistryFactory,MulticastRegistryFactory,ZookeeperRegistryFactory

2,newRegistryDirectory创建注册中心目录服务

3,registry.subscribe订阅服务,--》rpc远程访问registryService,RegistryDirectory作为NotifyListener

-->RegistryDirectory.notify(urls)-->urls-toInvokers//此时生成了接口及接口的方法对应的invoker列表

4,cluster.merge(directory)默认FailoverCluster生成FailoverClusterInvoker(RegistryDirectory)

创建invoker完成

III,创建代理(T)proxyFactory.getProxy(invoker)--》JavassistProxyFactory-》(T)Proxy.getProxy(interfaces).newInstance(newInvokerInvocationHandler(invoker));

使用Javassist创建了两个CLASS。

publicclassProxy1extendsProxy

implementsClassGenerator.DC

{

publicObjectnewInstance(InvocationHandlerparamInvocationHandler)

{

returnnewproxy1(paramInvocationHandler);

}

}

publicclassproxy1

implementsClassGenerator.DC,EchoService,DemoService

{

publicstaticMethod[]methods;

privateInvocationHandlerhandler;

publicStringsayHello(StringparamString)

{

Object[]arrayOfObject=newObject[1];

arrayOfObject[0]=paramString;

ObjectlocalObject=this.jdField_handler_of_type_JavaLangReflectInvocationHandler.invoke(this,jdField_methods_of_type_ArrayOfJavaLangReflectMethod[0],arrayOfObject);

return((String)localObject);

}

publicObject$echo(ObjectparamObject)

{

Object[]arrayOfObject=newObject[1];

arrayOfObject[0]=paramObject;

ObjectlocalObject=this.jdField_handler_of_type_JavaLangReflectInvocationHandler.invoke(this,jdField_methods_of_type_ArrayOfJavaLangReflectMethod[1],arrayOfObject);

return((Object)localObject);

}

publicproxy1(InvocationHandlerparamInvocationHandler)

{

this.jdField_handler_of_type_JavaLangReflectInvocationHandler=paramInvocationHandler;

}

}

返回proxy1xxx接口的子类。

4,动态代理背后的故事,以dubbo协议的通信为例

从生成的proxy1的代码我们可以看到sayHello(Stringstr)时调用了InvokerInvocationHandler.invoke(Objectproxy,Methodmethod,Object[]args)

-----》invoker.invoke(newRpcInvocation(method,args)).recreate();

这里的invoker是对com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker的层层包装,实现负载均衡、失败转移(FailoverClusterInvoker)、InvokerListener,InvokerChain的顺序调用。

由Protocol.refer生成。

如:FailoverClusterInvoker-》

publicResultinvoke(finalInvocationinvocation)throwsRpcException{

if(destroyed){

thrownewRpcException("Rpcinvokerfor"+getInterface()+"onconsumer"+NetUtils.getLocalHost()

+"usedubboversion"+Version.getVersion()

+"isnotdestroyed!Cannotinvokeanymore.");

}

LoadBalanceloadbalance;

List<Invoker<T>>invokers=directory.list(invocation);//从服务目录中找到所有的invoker,处理了router,目前router只有ScriptRouter实现。

if(invokers!=null&&invokers.size()>0){

//加载负载均衡算法

loadbalance=ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()

.getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY,Constants.DEFAULT_LOADBALANCE));

}else{

loadbalance=ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);

}

returndoInvoke(invocation,invokers,loadbalance);

}

publicResultdoInvoke(Invocationinvocation,List<Invoker<T>>invokers,LoadBalanceloadbalance)throwsRpcException{

if(invokers==null||invokers.size()==0)

thrownewRpcException("Noprovideravailableforservice"+getInterface().getName()+"onconsumer"+NetUtils.getLocalHost()+"usedubboversion"+Version.getVersion()+",Pleasecheckwhethertheservicedoexistorversionisrightfirstly,andchecktheproviderhasstarted.");

intlen=getUrl().getMethodParameter(invocation.getMethodName(),Constants.RETRIES_KEY,Constants.DEFAULT_RETRIES)+1;

if(len<=0)

len=1;

//retryloop.

RpcExceptionle=null;//lastexception.

List<Invoker<T>>invoked=newArrayList<Invoker<T>>(invokers.size());//invokedinvokers.

Set<URL>providers=newHashSet<URL>(len);

//挨个试,如果失败就继续。实现Failover。

for(inti=0;i<len;i++){

//booleanpp=false;//isproviderproblem.

Invoker<T>invoker=select(loadbalance,invocation,invokers,invoked);

invoked.add(invoker);

providers.add(invoker.getUrl());

try{

returninvoker.invoke(invocation);

}catch(RpcExceptione){

if(e.isBiz())throwe;

le=e;

//pp=true;

}catch(Throwablee)//bizexception.

{

thrownewRpcException(e.getMessage(),e);

}finally{

//if(pp)//ifproviderproblem,failover.

//inv.setWeight(0);

}

}

List<URL>urls=newArrayList<URL>(invokers.size());

for(Invoker<T>invoker:invokers){

if(invoker!=null)

urls.add(invoker.getUrl());

}

thrownewRpcException(le.getCode(),"Tried"+len+"timestoinvokeproviders"+providers+""+loadbalance.getClass().getAnnotation(Extension.class).value()+"selectfromallproviders"+invokers+"forservice"+getInterface().getName()+"method"+invocation.getMethodName()+"onconsumer"+NetUtils.getLocalHost()+"usedubboversion"+Version.getVersion()+",butnolucktoperformtheinvocation.Lasterroris:"+(le!=null?le.getMessage():""),le);

}

}

再来具体看看实际执行远程调用DubboInvoker:

DubboInvoker由com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol创建-》

public<T>Invoker<T>refer(Class<T>serviceType,URLurl)throwsRpcException{

//findclient.

intchannels=url.getPositiveParameter(Constants.CONNECTIONS_KEY,1);

ExchangeClient[]clients=newExchangeClient[channels];

if(channels==1){

clients[0]=getOrInitClient(url);

}else{

for(inti=0;i<clients.length;i++){

clients[i]=getOrInitClient(url);//默认初始化了一个LazyConnectExchangeClient-->init时Exchangers.connect(url,requestHandler);

}

}

System.out.println(serviceType.getName()+":"+clients.length);

//createrpcinvoker.

DubboInvoker<T>invoker=newDubboInvoker<T>(serviceType,url,clients);

invokers.add(invoker);

returninvoker;

}

在Protocol里创建了,ExchangeClient,及requestHandler

DubboInvoker.doInvoke(finalInvocationinvocation)-->(Result)currentClient.request(inv,timeout).get();调用ExchangeClient发起请求

默认通过NETTY框架通信。

见com.alibaba.dubbo.remoting.transport.netty.NettyClient

对协议的encode,decode实现:

com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec对于配置文件中的

<dubbo:methodname="subscribe">

<dubbo:argumentindex="1"callback="true"/>

</dubbo:method>

callback为true的,DubboCodec在服务端自动生成参数代理,通过RPC远程调用消费者的方法。此时的invoker为ChannelWrappedInvoker

ChannelWrappedInvoker发起的请求,由DubboProtocol得requestHandler处理received--》

if(messageinstanceofInvocation){

reply((ExchangeChannel)channel,message);

}

比如消费者subscribe时,com.alibaba.dubbo.registry.support.SimpleRegistryService处理完成后要调用消费者的NotifyLisenter.notify(urls)

消费者在发送请求时,DubboCodec根据URL中配置的方法的某一个参数的callback属性是否为true自动发布服务,以接受服务端的callback。


Remote模块分析

客户端:dubbo协议,netty实现

发送请求:

HeaderExchangeClient-->request-->

HeaderExchangeChannel-->request-->

-->req=newRequest()

-->DefaultFuturefuture=newDefaultFuture(channel,req,timeout);

-->NettyClient->send(req)

-->NettyChannel-->send(req,booleansent)

-->NettyHander-->writeRequested

--->encode

--->Netty->channel+writebuffer,writetask(放到IO线程的任务队列

--->NioWorker-->processWriteTaskQueue

--->write0(IO线程里发送数据

--->NettyClient-->sent

--->DefaultChannelHandler-->sent

--->HeaderExchangeHandler-->sent

--->DubboProtocolrequestHandler-->sent

--->DefaultFuture.sent(channel,request);

--->DefaultFuture.doSent()标记数据发送完的时间

接收返回结果:

--->decode

NettyHander-->messageReceived

--->DefaultChannelHandler--->received


-->(O线程解码完后,交给线程池处理。)

executor.execute(newChannelEventRunnable(channel,handler,ChannelState.RECEIVED,message));

-->ChannelEventRunnable-->run

-->HeaderExchangeHandler.received

----->HeaderExchangeHandler--》handleResponse

--->DefaultFuture.received(channel,response);

总体上说,dubboRPC做了很好的封装,能够实现透明的远程调用,在消费端实现了对于服务端调用的负载均衡算法、支持服务的集群。并且提供了监控接口,可通过WEB界面了解服务的情况(请求次数、有哪些服务、服务有几个提供者)等。提供的注册中心支持服务的注册、取消注册,并通知消费端服务列表的变更。

没时间排版,有兴趣的凑合着看吧。

<!--EndFragment-->

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值