模块介绍
- dubbo-admin:
- 控制台
- dubbo-cluster
- 集群
- 负载均衡
- loadbalance
- AbstractLoadBalance
- ConsistentHashLoadBalance
- LeastActiveLoadBalance
- RandomLoadBalance
- RoundRobinLoadBalance
- loadbalance
- dubbo-common
- 公共的逻辑模块
- 工具类
- json
- log
- …
- 工具类
- 公共的逻辑模块
- dubbo-config
- 配置层
- spring配置的集成
- 配置层
- dubbo-container
- 容器
- dubbo-demo
- 演示案例
- dubbo-filter
- 过滤器
- 验证
- 缓存
- 过滤器
- dubbo-maven
-
- dubbo-monitor
- 监测中心
- dubbo-registry
- 注册中心
- multicase
- redis
- zookeeper
- …
- 注册中心
- dubbo-remoting
- 远程通讯协议
- grizzly
- http
- mima
- netty
- netty4
- p2p
- zookeeper
- 远程通讯协议
- dubbo-rpc
- 远程传输协议
- dubbo协议的实现
- 远程传输协议
- dubbo-simple
- 简单的监控中心
- dubbo-test
-
- dubbo-lite
- hessian序列化协议的一个包
- dubbo对hessian做了改造,不是原生的hessian协议。
- hessian序列化协议的一个包
入口
- 基于App.java中的main方法去运行,main方法基于spring容器去启动。所以先到
dubbo-config
中找到dubbo-config-spring
。 - 使用dubbo时,都是基于自定义的dubbo配置。相当于对spring配置的一个扩展。需要自定义配置时使用的两个接口
- NamespaceHandler
- 注册BeanDefinitionParser,利用它来解析
- BeanDefinitionParser
- 解析配置文件的元素
- NamespaceHandler
- resources/spring.handlers
- 做spring扩展,默认加载。
- spring会默认加载jar包下/META-INF/spring.handlers 找到对应的NamespaceHandler
- com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler#init
- Main.main(args)—container.start()—context.start—init—DubboBeanDefinitionParser
- 解析
- application
- module
- registry
- monitor
- provider
- consumer
- protocol
- service
- reference
- annotation
- 单独处理
- ProtocolConfig
- ServiceBean
- ProviderConfig
- ConsumerConfig
- 解析
com.alibaba.dubbo.config.spring.ServiceBean
实现了
- InitializingBean
- 当spring容器初始化后,触发afterPropertiesSet方法
- DisposableBean
- Bean被销毁时,调用destroy方法
- ApplicationContextAware
- Bean注入成功以后,注入一个ApplicationContext对象,获取spring上下文
- ApplicationListener
- spring容器启动后,会触发事件通知
- BeanNameAware
- Bean初始化完成后,可以获得bean相关属性
afterPropertiesSet
方法
- 检查
Provider
、Application
、Module
、Registry
、Monitor
、Protocol
、Path
是否为空,如果为空,则赋值。 - 判断是否延迟,不延迟则发布服务export—doExport
- 获得注册中心的配置、多协议发布
com.alibaba.dubbo.config.ServiceConfig#doExportUrls
List<URL> registryURLs = loadRegistries(true);
- 如果协议名称没有配置,则采用dubbo协议
com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol
- 获得host
- 获得port
com.alibaba.dubbo.config.ServiceConfig#findConfigedPorts
- 解析环境变量配置的port
- 取协议的默认端口(dubbo默认20880)
- 都没有,则随机生成
- 用Map<String, String>来存储配置信息
- dubboVersion
- timestamp
- pid
- application
- module
- provider
- …
- 根据
name
、host
、port
、path
、map
生成发布服务的URL - 如果register不为空,则将服务注册
- 通过
protocol.export
发布服务com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#export
- openServer—发布服务的URL存放到serverMap
com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer
ExchangeServer
为协议层的APIserver = Exchangers.bind(url, requestHandler);
com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchanger#bind
Transporters.bind
绑定传输协议- Grizzly
- Mina
- Netty
- Netty4
- 获得注册中心的配置、多协议发布
SPI机制
External Libraries
—dubbo-2.5.3.jar
—META-INF
—dubbo.internal
—com.alibaba.dubbo.rpc.Protocol
配置的是协议的实现(Key-Value)。
Netty的SPI机制就相当于一个插件化的支持。
原生SPI通过serviceLoader一次性加载,而在上述文件中会根据name
加载。
如何实现
- 创建类
MyProtocol
实现com.alibaba.dubbo.rpc.Protocol
接口及方法int getDefaultPort()
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
META-INF/services/
—META-INF/dubbo/
—META-INF/dubbo/internal/
这几个文件夹皆可- 创建
com.alibaba.dubbo.rpc.Protocol
文件 - 写入
myprotocol=com.bai.dubbo.demo.MyProtocol
- 创建
App
类内Protocol protocol=ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("myprotocol");
- 可以获得到自定义端口
dubbo源码
com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol
Exporter<?> exporter = protocol.export(invoker);
会通过动态代理的方式生成动态类ProtocolAdaptive
。
com.alibaba.dubbo.common.extension.Adaptive
每一个扩展里都有一个自适配的Adaptive,如果没有配置自定义协议,则采用dubbo协议。
Adaptive注解可以放在类上也可以放在方法上。
通过扩展去调用方法,会有getAdaptive方法,在协议里有自适配的Adaptive。
com.alibaba.dubbo.common.extension.ExtensionLoader
getExtensionLoader
- 判断类是否为null,为null报错
- 判断是否为接口,不是接口报错
- 判断带SPI注解,没带SPI注解报错
- 每个定义的SPI的接口都会构建一个ExtensionLoader实例,存储在
ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
- 从
EXTENSION_LOADERS
里取类对应的ExtensionLoader实例,如果为null
,则new
一个,再存储到EXTENSION_LOADERS
里
带参构造
- 找到一个适配的Extension
getAdaptiveExtension
createAdaptiveExtension
A类内有成员变量B类,B类继承了C类。通过SPI扩展时,如何判断需要注入的是B还是C。此方法会生成一个Adaptive。
- ProtocolFilterWrapper
- 根据invoker的url的协议判断该协议是该注册还是该发布
- registry
- RegitstryProtocol
- dubbo
- DubboProtocol
- registry
- 根据invoker的url的协议判断该协议是该注册还是该发布
- ProtocolListenerWrapper
loadFile
- 启动初始化时,会填充ExtensionLoader类的一些缓存数据(cacheXXX),从目录中(
META-INF/services/
—META-INF/dubbo/
—META-INF/dubbo/internal/
)读取,通过ClassLoader去加载。 - 逐行读取com.alibaba.dubbo.rpc.Protocol里的内容,
- 有
@Adaptive
,则将此类作为Protocol协议的适配,加载到缓存(cahedNames)里,然后根据name找到class,再去通过ClassLoader实例化(new Instance()) - 没有
@Adaptive
,适配类通过javassist修改字节码生成。- 判断实现类是否存在入参为接口的构造器(就是DubbboProtocol类是否还有入参为Protocol的构造器),有的话作为包装类缓存到此ExtensionLoader的Set<Class<?>>集合中,这个其实是个装饰模式
- 既不是适配对象也不是wrapped对象,那就是扩展点的具体实现对象,查找
@Activate
- 有,缓存到cachedActivates
- 有
服务消费
根据dubbo内配置的dubboReference加载spring配置。
com.alibaba.dubbo.config.spring.ReferenceBean#afterPropertiesSet
最后会调用getObject
方法。跳转到com.alibaba.dubbo.config.ReferenceConfig#init
。判断—生成参数—createProxy
- 一个JVM内,会通过本地方式调用,否则用远程方式调用。
com.alibaba.dubbo.rpc.Invoker
,通过它去调用具体的服务refprotocol.refer
com.alibaba.dubbo.registry.integration.RegistryProtocol#refer
- 通过
proxyFactory.getInvoker
调用
- 通过
补充
dubbo核心设计
- exporter
- invoker
- protocol
- SPI
dubbo和dubbox有什么区别
dubbox是当当的架构师在dubbo的基础上做了升级后的开源框架
序列化—kryo
—比hessian序列化更好
dubbo执行代码的编译
- 利用JDk工具类变异
- 利用javassist根据源代码生成字节码
ObjectFactory是如何根据类型和名字来获取对象的
- ExtensionFactory
- AdaptiveExtensionFactory
- 持有所有ExtensionFactory对象的集合
- SpiExtensionFactory
- 优先查找
- 获取要被注入的对象,就是要获取dubbo spi扩展的实现,所以传入的参数类型必须是接口类型并且接口上打上了@SPI注解,返回的是一个设配类对象。
- SpringExtensionFactory
- SpiExtensionFactory获取结果为null再在此查找
- Dubbo利用spring的扩展机制跟spring做了很好的融合。在发布或者去引用一个服务的时候,会把spring的容器添加到SpringExtensionFactory工厂集合中去, 当SpiExtensionFactory没有获取到对象的时候会遍历SpringExtensionFactory中的spring容器来获取要注入的对象
- AdaptiveExtensionFactory
ObjectFactory也是基于dubbo的spi扩展机制的。
它跟Compiler接口一样设配类注解@Adaptive是打在类AdaptiveExtensionFactory上的。