Java中的SPI机制

  1. 可以了解下JDBC,支持MySQL、Oracle
  2. 一般启动的时候读取文件,比如jdbc用静态代码块处理该逻辑,提升性能
  3. 通过ServiceLoader.load(接口.class)获取所有接口实现,并自动实例化
  4. 底层就是基于反射实现
  5. 缺点:如果实现过度,容易造成实例创建浪费,不支持有针对性加载

Dubbo的SPI

  1. 解决JAVA总的SPI的不足
  2. 可根据配置指定加载具体某个接口的实现
  3. 具体使用 ExtensionLoader,可查看其源码
  4. 类似Spring,Dubbo基于SPI还是实现了AOP特性
  5. AOP是基于接口的Wraper实现类而实现
  6. Holder包装了SPI中的实现,解决并发调用问题
  7. Dubbo中的SPI还支持依赖注入,核心通过代理对象和动态编译实现
  8. 依赖注入内接口多实现时,通过URL机制
  9. dubbo的依赖注入不会出现循环依赖,因为依赖注入的是代理对象
  10. 根据接⼝的全限定名去以下⽬录下寻找对应的⽂件,里面逻辑还会涉及到版本兼容
    • META-INF/dubbo/internal/
    • META-INF/dubbo/
    • META-INF/services/

Dubbo中的IOC与AOP

  1. 根据当前实例,通过setter方法注入
  2. 特殊点在于Dubbo通过自己的spi机制得到的是一个代理对象进行注入
  3. 最终还是通过反射调用setter方法注入属性
  4. Dubbo内部简单实现了AOP,原理就是利用Wrapper包装类
  5. 对象在实例化完成后,就会被一些Wrapper类进行包裹
  6. 自适应扩展点,可以利用@Adaptive注解实现
  7. 通过@Adaptive注解,可以指定某个类为某个接⼝的代理类

与Spring集成的原理

  1. Spring启动时,主要做三件事情:

    • 解析.propertiles配置文件
    • 处理@Service注解(Dubbo的)
    • 处理@Reference
  2. 核心原理入口可以找到@EnableDubbo注解

    • EnableDubbo注解上又衍生两个关键注解
    • @EnableDubboConfig
    • @DubboComponentScan
  3. DubboConfigBindingRegistrar

    • 获得配置文件内容
    • 解析配置
    • 生成BeanDefinition
  4. DubboComponentScanRegistrar

    • 向Spring容器中注册两个Bean
    • ServiceAnnotationBeanPostProcessor
    • ReferenceAnnotationBeanPostProcessor
  5. ServiceAnnotationBeanPostProcessor

    • 注册bean定义
    • 扫描Dubbo的@Service注解
    • 进行Dubbo服务的导出

Dubbo的可扩展机制SPI及与Spring集成源码解析-LMLPHP

  1. ServiceBean

    • 关键对象,表示⼀个Dubbo服务
    • ref,表示服务的具体实现类
    • interface,表示服务的接⼝
    • parameters,表示服务的参数
    • application,表示服务所属的应⽤
    • protocols,表示服务所使⽤的协议
    • registries,表示服务所要注册的注册中⼼
  2. ReferenceAnnotationBeanPostProcessor

    • 寻找@Reference注入点,并将其缓存
    • 找到注入点后,以其所在类生成一个代理对象
    • 生成代理对象需要考虑:a.导入的服务是不是本地就存在;b.导入的服务是否已经被引入过;
    • 关键实现就是利用ServiceBean的name设计:接口类型+group+version+作为beanName
    • 服务调用者在引入服务时,通过referenceBeanName从缓存中查找
    • 缓存中不存在,则创建一个ReferenceBean
    • 再通过referencedBeanName判断当前容器中是否存在该bean
    • 如果存在,则表示引入的服务在本地,生成一个代理对象并缓存到localReferenceBeanInvocationHandlerCache
    • 如果不存在,则调用ReferenceBean的get()⽅法得到⼀个代 理对象
06-18 20:32