dubbo spi扩展
dubbo扩展利用java的spi机制,使高层引用底层,用户可以通过spi扩展dubbo。
java spi
通过在META-INF目录创建services
文件夹,然后以接口全限定名
作为文件名,多个实现类的权限定名
为文件内容,通过ServiceLoader
类的load方法传入接口class,即可获取到所有实现类。原理是通过在指定目录查找该类的文件,从文件中获取权限定名并创建对象。
dubbo
dubbo没有直接使用java spi,而是实现一套类似的机制,增加了一些功能。
通过在META-INF目录dubbo
文件夹存放配置文件,文件名命名方式与java spi一样,不同的是,文件内容以键值对
的方式,可以对象名为key,value为实现类的全限定名。通过ExtensionLoader
可以获取实现类,并且可以通过key直接获取对应的实现对象。
源码在ExtensionLoader,主要就是现将指定目录配置的所有扩展类通过反射实例化,然后放入通过key value形势存到缓存中。通过指定获取的扩展类key,获取到对应实现类。之后为实现类设置依赖,通过实例中的set方法进行设置,这是dubbo的ioc机制
服务导出
服务通过注册spring上下文刷新事件,在spring初始化会开始导出服务。
源码ServiceBean
。
获取配置信息,通过解析xml,开始服务导出。
- 通过
NettyServer
启动一个服务,创建Netty包下的ServerBootstrap启动服务。底层基于nio的ServerSocketChannel
启动一个服务,监听端口。 - 向注册中心注册服务。
源码在ZookeeperRegistry,先根据zk配置信息创建zk连接客户端,再以 分组名/接口全限定名/provider/${url} 目录下创建一个临时节点,即创建一个文件代表一条注册信息。默认分组名为dubbo
。
服务引用
Dubbo 服务引用的时机有两个,
- Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务
- ReferenceBean 对应的服务被注入到其他类中时引用。默认是第二种,用到才注入。
在类ReferenceBean中,引用bean通过实现spring的FactoryBean的getObject方法,定义生成引用bean的方式,该方法最终调用了ReferenceConfig
的init方法,该方法先生成消费者配置类,然后判断是jvm本地引用还是远程引用,如果有直接连接服务的url或者url参数是远程作用域、本地导出的服务没有包含当前服务
等等情况则为远程。
如果url只有一个地址,则直接生成invoke
对象。invoke调用通过NettyChannel
发送消息,通过ChannelFuture获取调用结果。
如果有多个url则会有多个invoker对象封装成cluster
对象,获取到一个合并后的inoker对象。最后生成引用类代理对象,如果不是生成代理对象,则客户端需要直接依赖invoker对象,造成代码侵入。
dubbo默认生成代理通过javassistProxy
,好处时执行代理方法比jdk快,但是生成代理类比jdk慢.
invoke调用服务默认时通过netty
通信。
通过配置可以修改代理方式为jdk
<dubbo:provider proxy=“jdk” />
xml解析,将bean注入spring
源码: DubboBeanDefinitionParser.parse()
为bean生成BeanDefinition注册到spring中,引用bean会实现factoryBean,调用bean时会通过getObject获取实际的bean,getObject会返回一个代理对象,由代理对象与服务端进行网络通信获取处理结果。
集群容错
服务目录
根据服务提供者配置生成的invoke对象集合,而且集合的内容会跟随注册中心服务的变化而变化。源码在RegistryDirectory
.
服务路由
条件路由,决定了消费端的调用目标。通过配置路由规则,可以限制某些服务提供者只可以被某些服务消费者调用。相当于服务网关的。源码在ConditionRouter
,对配置进行解析匹配。
集群
由于服务提供者大部分情况是会部署多台机器,dubbo通过封装Cluster接口,将多个invoke合并成一个,消费端只需要通过这个inovke进行调用,不用底层具体调用了哪个api