转自 :http://blog.csdn.net/HEL_WOR/article/details/52940399?locationNum=3&fps=1
1.rpc
核心:动态代理
consumer:接口进行动态代理,在InvocationHandler构造代理对象,写入方法名,请求参数,参数类型。
provider:获得消息,反射调用实现类,返回结果。
reactor使用netty。
中间层使用zookeeper或Redis作为注册中心,涉及发布订阅,本地缓存提供者信息,通过路由规则筛选->负载均衡选择合适地址调用。
motan rpc流程一致,代理+netty。
2.Filter
责任链模式实现
consumer端,使用代理对象触发ProtocolFilterWrapper类的buildInvokerChain执行。这一步构造Filter调用链。
允许扩展的类或者扩展实现的接口需有@SPI注解,比如Filter。
扩展的实现需打上@Active注解,比如如自定义Filter。
dubbo从txt文本中加载类:
- 1
- 2
- 3
- 1
- 2
- 3
对应目录:
默认加载:
自定义Filter,需在META-INF/dubbo或者META-INF/services下加入com.alibaba.dubbo.rpc.Filter文本。上述已解释了这样做的原因。
外部实例链接:给dubbo接口添加白名单——dubbo Filter的使用。
3.路由
ProtocolFilterWrapper的构造代理开始。
首次运行,RegisterProtocol。
不构造本地代理。向zookeeper注册consumer地址。构造RegistryDirectory,设置路由等信息,缓存本地。
二次运行,DubboProtocol,构造本地代理。
路由信息缓存本地->代理触发->路由->负载均衡
路由逻辑程序启动时开始执行,在从注册中心拿到服务提供者地址后开始选择router的实现类。路由信息缓存本地。
启动完成后,调用调用代理,进入invoke逻辑。然后负载均衡逻辑。可以看到负载均衡也是通过SPI扩展。
开始选择路由。
提供路由的意义:分布式服务通常集群部署,意味着一个集群中有这个服务的多个实例,如何让consumer有选择性的调用某一个(类)特定的服务提供者就是路由的职责。
自定义路由,观察setRouters函数,从url.getParameter(Constants.ROUTER_KEY)入手,即构造URL,META/INF-dubbo下新增扩展文本。
4.请求的传输?
dubbo默认使用netty作为底层通信组件。
发送请求:Channel接口NettyChannel实现下send方法。调用netty的write方法写入数据。请求格式:
请求服务器:NettyServer类
请求处理:NettyHandler下receive方法,此为IO线程,接收到的消息会被此线程扔进线程池交给业务线程处理,IO线程继续监听事件。
业务线程处理此消息,判断是否为心跳,request,还是response。
如果是request,进入HeaderExchangeHandler类调用handleRequest方法,最终调用DubboProtocol的reply方法执行反射调用获取结果再将结果写入netty的channel发送到请求方。
5.本地方法请求是如何传输到远程服务被调用的?
远程方法调用,将本地方法名,请求参数,参数类型通过网络传输到远程服务,远程服务找到请求方法所在接口的实现类,通过反射运行请求方法返回结果。+
在服务端如何找到这个接口的是实现类?请求中会带上这个方法所在的接口,服务端在启动暴露服务时会将暴露服务的interface和实现做成map缓存起来。在下图中暴露的服务放在了exporterMap中,通过serviceKey获取,serviceKey即为接口名称。