接上一篇博客《Dubbo源码深度解析(六)》,上篇博客主要从服务消费方开始讲起,主要讲:如果类中的属性或者方法,如果被@DubboReference注解所修饰,Dubbo是怎么处理的,处理逻辑类似Spring框架提供的@Autowired注解。核心就是ReferenceAnnotationBeanPostProcessor类,最终会生成一个对应的ReferenceBean对象,并放入Spring容器,当然最终给属性进行依赖注入的并非ReferenceBean对象,而是它的 ref属性,如果该属性为空,就需要调用Protocol#refer()方法(Dubbo的SPI机制找到Protocol接口的实现类,调用实现类的ref()方法)创建Invoker,最终生成代理对象还没讲到,这篇博客会讲到。然后就是主要讲如何创建Invoker对象,也涉及到从注册中心拉取服务提供方的地址,以及Netty Client是如何跟服务提供方建立连接的逻辑等。
本篇博客是Dubbo源码讲解的最后一篇,在本篇博客中,会接着上篇的内容继续讲,上篇最后讲到了服务消费方跟服务提供方建立连接,其实讲到这里,Invoker对象的创建也基本讲完了。有一个核心的方法没有讲到,即RegistryProtocol#doCreateInvoker()方法中风格的这一行代码:
前面也讲到了,这里的cluster对象实际上是MockClusterWrapper对象,而MockClusterWrapper对象的cluster是FailoverCluster对象,看看MockClusterWrapper#join()方法,代码如下:
先看看FailoverCluster#doJoin()方法,代码如下:
再看看AbstractCluster#buildClusterInterceptors()方法,代码如下:
先看看ClusterInterceptor接口,代码如下:
org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor文件的内容为:
实现类的代码分别是:
讲ExtensionLoader#getActivateExtension()方法的时候,有一点没有讲到,也就是过滤条件的这个地方:
因此最终获取到的只有ConsumerContextClusterInterceptor对象,最终创建的InterceptorInvokerNode对象的interceptor属性为ConsumerContextClusterInterceptor对象,next属性为FailoverCluster对象。断点验证,结果如下:
到这里为止,生成Invoker对象的逻辑讲完了。总结一下,最终在ReferenceConfig得到的Invoker是什么样的?或者说是经过了多少层包装?
通过上面这些截图可以知道,最终生成的Invoker对象为:MigrationInvoker对象,而MigrationInvoker对象的invoker属性为MockClusterInvoker对象;而MockClusterInvoker的对象的invoker属性为InterceptorInvokerNode对象;而InterceptorInvokerNode对象interceptor属性为ConsumerContextClusterInterceptor对象,next为FailoverClusterInvoker对象;FailoverClusterInvoker对象里面有个urlInvokerMap属性,key为URL,value为InvokerDelegate对象,而InvokerDelegate的invoker属性为FilterNode对象;而FilterNode对象的filter属性为ConsumerContextFilter属性,它的next属性仍是FilterNode对象;而这个FilterNode对象的filter属性为FutureFilter对象,它的next属性仍是FilterNode对象;这个FilterNode对象的filter属性为MonitorFilter对象,next属性为ListenerInvokerWrapper对象;而ListenerInvokerWrapper对象的invoker属性为AsncToSyncInvoker对象;AsncToSyncInvoker对象的invoker属性为DubboInvoker对象,其中DubboInvoker的clients存放的对象,才是真正跟服务提供方建立连接的客户端(有朋友可能好奇,整理清楚这层层的包装有啥用?用处大了,理顺了才能知道调用链路,也能知道每一层包装的作用是啥,可能其中某一层就做了服务的负债均衡)。断点验证,结果为:
回到ReferenceConfig#createProxy()方法,最终得到的Invoker就是那个上面我讲的,位置为:
这里的PROXY_FACTORY属性即为ProxyFactory$Adaptive,即调用ProxyFactory$Adaptive#getProxy()方法,代码如下:
很明显这里的InvokerInvocationHandler实现了InvocationHandler接口,因此在真正执行的是时候,调用的是InvokerInvocationHandler#invoke()方法,断点看看依赖注入的结果:
接下来就是发起远程调用的,即调用HelloService#sayHello()方法,最终调用的是InvokerInvocationHandler#invoke()方法,代码如下:
有前面讲的可知,InvokerInvocationHandler对象的invoker属性为MigrationInvoker对象,因此直接看MigrationInvoker#invoke()方法,代码如下:
看看MigrationInvoker#checkInvokerAvailable()方法,代码如下:
由于是取反,因此最终调用invoker#invoke()方法,代码如下:
有前面可知,构建的InterceptorInvokerNode链只有一个,而这里的interceptor属性是ConsumerContextClusterInterceptor对象,因此可以看看ConsumerContextClusterInterceptor的before()方法和after()方法,代码如下:
重点看看ClusterInterceptor#intercept()方法,代码如下:
先看看是如何获取Invoker的集合的,看看AbstractClusterInvoker#list()方法,代码如下:
看看RouterChain#route()方法,代码如下:
上一篇博客讲到过,此时routers属性中有四个Router对象,顺序分别是:MockInvokersSelector、TagRouter、AppRouter和ServiceRouter。常用的有TagRouter和ConditionRouter,但默认是不加载ConditionRouter的,需要指定。可以通过环境变量来指定,核心方法为:AbstractConfig#refresh()方法,ReferenceBean是其类,看看该方法,代码如下:
再看看CompositeConfiguration#getString()方法,传入的当然是解析后的Setter方法的名字,如setRouter() => "router",代码如下:
实际上就是在AbstractConfig#refresh()方法中创建的CompositeConfiguration对象,回去看看,代码如下:
因此可以知道 ,prefix的值为:dubbo.reference.接口全限定名,因此可以这样设置,代码如下:
断点验证,结果为:
当然,还可以用Dubbo的配置文件,即dubbo.properties,如下:
当然也可以通过@DubboReference注解指定,由于注解中没有直接提供 router属性,因此需要这样指定:
处理@DubboReference注解的parameters属性的代码在这里:
回到之前说的,主要看TagRouter和ConditionRouter的使用方法。先说TagRouter,这是给服务消费方和服务提供方发打上标签,只有服务消费方的tag和服务提供方的tag一直才能调用,前置准备,先是服务提供方配置:
启动服务提供方服务,再在做如下修改:
再次启动服务提供方的服务,再看看Nacos,结果如下:
再配置服务消费方,配置如下:
启动服务消费方服务,直接看RegistryDirectory#doList()方法,并打断点,结果如下:
未完待续(明天继续完善本篇博客)