服务引用过程解析
调用服务时,在XML中配置<dubbo:reference>
和注册中心即可像调用一个内存方法一样调用远端服务。
1 | <dubbo:registry address="multicast://224.5.6.7:1234"/> |
<dubbo:reference>
同样是由DubboBeanDefinitionParser
进行解析,其被解析后成实例ReferenceBean
。因此,其是服务引用过程的关键。
可以看出,它是一个工厂Bean(实现FactoryBean
接口)、InitializingBean
接口。因此当有服务引用demoService
时,会调用getObject()
返回代理的对象。所以getObject()
即是关键服务。因为实现了InitializingBean
所以在向Spring暴露bean之前会调用afterPropertiesSet
方法。RefrenceBean
的afterPropertiesSet
方法作用跟ServiceBean
的afterPropertiesSet
一样,从Spring容器中获取Consumer
、Application
、Module
、Registeries
、Monitor
、Protocol
对象设置到其属性中。
1 | public void afterPropertiesSet() throws Exception { |
getObject
最终会调用init
方法,init
方法中会组装所有配置的属性然后根据这些属性来创建代理对象createProxy
1 | private void init() { |
当配置injvm=true
时,且当前JVM有对应服务时,createProxy
会直接应用本地的服务,本章为了涵盖更多的内容,因此会专注于远端服务引用的情况。
1 | private T createProxy(Map<String, String> map) { |
proxyFactory
是个扩展点,有JdkProxyFactory
和JavassistProxyFactory
。进一步可以看到,配置的拦截器都是InvokerInvocationHandler
。因此当调用Client
方法时,都会被其拦截,调用其invoke
方法。
1 |
|
1 | public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { |
可以看出,实际上Router
的作用是起过滤作用的,过滤出所有符合条件的Invoker
。
再来继续看下第一次订阅或者当服务提供者信息发生改变时注册中心通知目录的逻辑:
1 | public synchronized void notify(List<URL> urls) { |
DubboProtocol.refer
用来创建传输层的Clients,并建立长连接。
1 | public <T> Invoker<T> refer(Class<T> serviceType, URL url) throws RpcException { |
getClients
会间接调用某种类型(XxxTransporter
)的传输器connect
方法。
1 | `getClients` |
另外一方面,值得一提的是HeaderExchangeClient
和HeaderExchangeServer
,都带有心跳功能,他们会周期扫描当前所有的Channel
,如果该Channel
最近一个周期内没被读或写的话,则发送一次心跳请求,若心跳超时则进行重连。
1 | public HeaderExchangeClient(Client client, boolean needHeartbeat) { |
针对的,在NettyServer
和NettyClient
构造函数里,可以看到ChannelHandlers.wrap(handler...)
这段逻辑。深入进去后会发现:
1 | protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) { |
会在ChannelHandler中嵌入一个HeartbeatHandler
,用来处理心跳请求:
1 | public void received(Channel channel, Object message) throws RemotingException { |