模块介绍

  • dubbo-admin:
    • 控制台
  • dubbo-cluster
    • 集群
    • 负载均衡
      • loadbalance
        • AbstractLoadBalance
        • ConsistentHashLoadBalance
        • LeastActiveLoadBalance
        • RandomLoadBalance
        • RoundRobinLoadBalance
  • 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协议。

入口

  • 基于App.java中的main方法去运行,main方法基于spring容器去启动。所以先到dubbo-config中找到dubbo-config-spring
  • 使用dubbo时,都是基于自定义的dubbo配置。相当于对spring配置的一个扩展。需要自定义配置时使用的两个接口
    • NamespaceHandler
      • 注册BeanDefinitionParser,利用它来解析
    • BeanDefinitionParser
      • 解析配置文件的元素
  • 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方法

  • 检查ProviderApplicationModuleRegistryMonitorProtocolPath是否为空,如果为空,则赋值。
  • 判断是否延迟,不延迟则发布服务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
    • 根据namehostportpathmap生成发布服务的URL
    • 如果register不为空,则将服务注册
    • 通过protocol.export发布服务
      • com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#export
      • openServer—发布服务的URL存放到serverMap
        • com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer
        • ExchangeServer为协议层的API
        • server = Exchangers.bind(url, requestHandler);
          • com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchanger#bind
          • Transporters.bind绑定传输协议
            • Grizzly
            • Mina
            • Netty
            • Netty4

SPI机制

External Librariesdubbo-2.5.3.jarMETA-INFdubbo.internalcom.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
  • 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容器来获取要注入的对象

ObjectFactory也是基于dubbo的spi扩展机制的。

它跟Compiler接口一样设配类注解@Adaptive是打在类AdaptiveExtensionFactory上的。