Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

本文是Dubbo第三讲:Dubbo的可扩展机制SPI源码解析

文章目录

      • 1、Dubbo SPI机制
        • 1.1、Dubbo具有良好拓展性的原因
        • 1.2、Dubbo SPI和Java SPI的区别?
        • 1.3、Dubbo SPI可认为是IOC实现吗?
      • 2、SPI机制在商品中心的应用
        • 2.1、TMF校验器
        • 2.2、在AfterImage应用中的使用
          • 2.2.1、整体流程图如下所述
        • 2.2.2、业务逻辑
      • 3、SPI总结

1、Dubbo SPI机制

1.1、Dubbo具有良好拓展性的原因

  • 1、整个框架中针对不同的场景,恰到好处地使用了各种设计模式
  • 2、基于Dubbo SPI 加载机制,让整个框架的接口和具体实现完全解耦合
  • Dubbo SPI 扩展
    • 与Java SPI类似,需要在META-INF/dubbo/下放置对应的SPI配置文件,文件名称需要命名为接口的全路径名。配置文件的内容为 key=扩展点实现类全路径名,如果有多个实现类则需要使用换行符分割
    • 在Dubbo启用时,会默认扫描这三个目录下的配置文件:META-INF/services/、META-INF/dubbo/、META-INF/dubbo/internal/
  • 1、dubbo filter详解
    • todo

1.2、Dubbo SPI和Java SPI的区别?

Dubbo的扩展点加载从JDK标准SPI(Service provider Interface)扩展点发现机制加强而来。
改进了JDK标准SPI的以下问题:

1、JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但是没用上也加载,会很浪费资源。(我的代码中初始化配置项也存在这样的问题)
2、如果扩展点加载失败,连扩展点的名称都拿不到了
3、增加了对扩展点IOC和AOP的支持,一个扩展点可以直接setter注入其他扩展点。

1.3、Dubbo SPI可认为是IOC实现吗?

todo

2、SPI机制在商品中心的应用

2.1、TMF校验器

详情见这个项目
项目实战第十六讲:使用开闭原则实现商品价格规则引擎

2.2、在AfterImage应用中的使用

2.2.1、整体流程图如下所述

Dubbo第三讲:Dubbo的可扩展机制SPI源码解析_第1张图片

2.2.2、业务逻辑

残影系统,使用切面实现的

  • 注解:Afterimage

    • 包含的字段有
      • captorConfig 本次使用的captor(捕获)配置
        • 该类包含两字段 Captor,dubbo接口或其他 config dubbo接口详情,具体结构见下文
      • expireMills 超时时间,单位是毫秒,小于1:不过期;大于1:过期;不配置:使用captor侧配置的过期时间
  • 使用场景:缓存dubbo调用结果,用于优化在执行上下文重复同一dubbo调用

    • 当同个线程执行链路,多次使用此注解时,只有最外层的注解生效
    • 加上此注解的方法,耗时调用将被暂存起来,直到退出方法
    • 注意事项:
      • 必须使用在能被spring AOP代理的方法上
  • 如何使用:

    • 引入依赖

    • <dependency>
          <groupId>cn.gov.zcygroupId>
          <artifactId>afterimage-integration-zcyartifactId>
          <version>2.0.0-SNAPSHOTversion>
      dependency>
      
  • 如果是spring,请使用注解 @EnableAfterimage开启, 然后在需要的方法(可被spring aop切面)加上注解@Afterimage开启。

    • eg: 1、启动时开启Afterimage,如果是spring boot 环境,会自动配置开启,

      • 如果spring-boot,不想启动时自动开启可配置afterimage.spring.bootstrap.enabled=false
    • @EnableAfterimage
      public class Application{
          
      }
      
    • 开启后,使用在需要优化的方法(可被spring aop切面),使被注解的方法开启afterimage

      • 如果想在运行时关闭,请配置:afterimage.spring.enabled=false
    • public class ItemServiceImpl{
          @Afterimage
          public Item find(){        
          }
      }
      
  • 执行流程

    • 1、afterimage-config 以扩展配置读取、监听的扩展

      • 第一块:apollo配置获取,监听事件变更

      • 第二块:spring配置 ,将残影实例自动配置到Spring中

      • config 扩展

        • 实现此cn.gov.zcy.afterimage.core.config.Config接口,可用于配置读取的扩展。 还需要实现ObjectProvider用来生成Config实例

        • 接口:Config

          • 作用:统计每个dubbo方法的缓存时间

          • 定义的方法:default get(key,defaultValue)、get(key)、default ddListener(key,configListenr) 如果对应key发生变化,调用listener、default removeListener(configListenr) 移除监听器、default removeListener(key, configListenr) 移除监听器

          • 实现类1

            • ApolloConfig(apollo配置)
            • 继承apollo的ConfigChangeListener接口实现了ApolloListener,实现其onChange事件
              • onChange方法里面,遍历所有改变的key,如果等于当前key,监听其改变
              • 补充了addListener方法和removeListener方法
              • 使用了写时复制ArraySet,因为配置读取的场景读多写少
            • 组合apolloConfig,并实现了Config的get方法,底层调用apolloConfig的getProperty方法
              • 实现了addListener(key,configListenr)方法,先创建监听,然后添加监听,如果apolloListener监听的数量等于1,底层调用apolloConfig的addChangeListener方法
              • 实现类removeListener(configListenr)方法,apolloListener移除监听,检查ApolloListener,为空则移除
              • 实现类removeListener(key, configListenr)方法,获取apolloListener监听器,如果为空,返回,否则,移除监听器,检查ApolloListener,为空则移除
          • 实现类2

            • SpringConfig(Spring配置)
              • 先实例化自身,然后获取系统参数
              • 实现了get(key)方法,如果系统参数为空,抛错,否则,有key获取系统参数
          • 实现类3

            • CompositeConfig(组合配置)
              • 实现了get(String key)方法,遍历每一个configList,查询config,如果能找到值,返回,否则,返回null
              • 实现了addListener(key, ConfigListener),给configList添加监听器
              • 实现了removeListener(ConfigListener)方法, 给configList移除监听器
              • 实现了removeListener(key, ConfigListener)方法, 给configList移除监听器
          • 实现类4

            • SystemConfig (系统配置)
              • 实现了get(key)方法,获取系统的值
          • 读取配置的顺序

            • apollo配置

              • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置, 格式如:order,name,providerClass,选择时,order小的优先,可以以#开头在上一行添加注释

                • 100,ApolloConfig,cn.gov.zcy.afterimage.config.apollo.ApolloConfigProvider

              • Apollo环境可引入afterimage-config-apollo来支持apollo的配置读取、以及动态配置监听

                • <dependency>
                      <groupId>cn.gov.zcygroupId>
                      <artifactId>afterimage-config-apolloartifactId>
                      <version>1.0-SNAPSHOTversion>
                  dependency>
                  
            • Spring配置

              • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置

                • 0,SpringConfig,cn.gov.zcy.afterimage.config.spring.SpringConfigProvider

            • 系统配置

              • 在resources资源文件夹下的META-INF/afterimage/ConfigProvider.def中配置

                • 1000,SystemConfig,cn.gov.zcy.afterimage.core.config.SystemConfigProvider

            • 默认配置为spring优先、apollo次之、System.getProperty最低

          • 配置的读取将按照spi的order配置,顺序从小到大读取,取到第一个不为null则返回

            • 也可以再启动时,设置-Dafterimage.config.order=SpringConfig,ApolloConfig 指定顺序,未指定的配置扩展将按默认顺序对应追加在后面
        • ObjectProvider 接口
          • 提供的方法:get()
          • 实现类
            • 实现类1、ApolloConfigProvider
              • NameSpace:afterimage.apollo.namespace
              • 实现了get()方法 --》从系统参数中获取名称空间,如果名称空间非空,获取apollo中当前名称空间的配置,否则:获取apollo “application”名称空间的配置项
            • 实现类2:SpringConfigProvider
              • 实现了get()方法 --》从SpringConfig获取实例
            • 实现类3:SystemConfigProvider
              • 实现了get()方法 --》获取SystemConfig实例
            • 实现类4:NopAlbumProvider
              • 实现了get()方法 --》获取NopAlbum实例
            • 实现类5:SoftReferenceAlbumProvider
              • 实现了get()方法 --》获取软引用类型ReferenceAlbum实例
            • 实现类6:StrongReferenceAlbumProvider
              • 实现了get()方法 --》获取强引用类型ReferenceAlbum实例
            • 实现类7:WeakReferenceAlbumProvider
              • 实现了get()方法 --》获取虚引用类型ReferenceAlbum实例
    • 2、afterimage-album 扩展调用结果的存储

      • 目前为空

      • 实现此cn.gov.zcy.afterimage.core.album.Album接口,可用于结果存储的扩展。 还需要实现ObjectProvider用来生成Album实例

      • 接口:Album

        • 作用:存储dubbo接口调用结果

        • 定义的方法

          • init() 初始化,
          • destory() 销毁,
          • write(contextId,key,value,超期时间)存入数据,获取残影系统上下文数据,如果值为空,返回;如果上下文为空,抛错,获取上下文中的超期时间,如果这个时间为空,取入参中传递过来的超期时间,写入;
          • dowrite(contextId,key,value,超期时间)方法, 为null或小于1,将不过期
          • read(ContextId contextId, String key) 读取
          • clear(ContextId contextId, String key) 清理
          • clear(ContextId contextId) 清空整个context
        • 实现类

          • 实现类1:抽象类 AbstractAlbum
            • 实现了dowrite(contextId,key,value,超期时间)方法,获取-当不存在时,创建新的上下文,组装ValueWrapper(value,超期时间,系统时间)
            • 实现了read(ContextId contextId, String key),获取上下文,如果为空,return,否则 --》获取valueWrapper ,如果没有超期(时间为空或者小于1ms)–》返回valueWrapper中值 --》如果有配置超期时间,获取当前时间,减去valueWrapper中的系统时间,比较valueWrapper中的超期时间,如果大于 --》移除上下文,否则返回valueWrapper中的值
            • 实现了clear(ContextId contextId, String key), 获取上下文,移除对应的key
            • 提供了两抽象类
              • 1、getOrCreate(contextId) 获取或创建上下文
              • 2、get(ContextId contextId) 获取上下文
            • 实现类:ReferenceAlbum
              • Map类型 字段album,使用了ValueReference(有三个实现类,后面讲解)
              • 字段strength,枚举类型(STRONG强引用 SOFT软引用 -在内存不足时回收,每MB空余可保留1s,WEAK弱引用-GC就被回收 )
                • 提供了一个抽象方法referenceValue
                • 实现了三个静态内部类
                  • StrongValueReference实现ValueReference接口,实现了get方法
                  • SoftValueReference继承了SoftReference 实现了ValueReference
                  • WeakValueReference继承了WeakReference 实现了ValueReference
              • 实现了方法init()
              • 实现了方法destory() 调用 album的清理
              • 实现了方法clear() 调用 album的remove
              • 实现了父类的抽象方法getOrCreate(contextId) 由context获取album Map的value,如果为空,说明需要初始化,给album初始化一个空的map,否则,返回map
              • 实现了父类的抽象方法get(contextId) 由context获取album Map的value,如果为空,返回空,否则,返回map
          • 实现类2:NopAlbum
            • 实现了这几个方法,都是空实现
            • init()方法初始化
            • destory() 销毁
            • doWrite(ContextId contextId, String key, Object value, Integer expireTimeMills) 存入
            • read(ContextId contextId, String key) 返回null
            • clear(ContextId contextId, String key) 清除第一个
            • clear(ContextId contextId) 清空
          • 实现类3:ReferenceAlbum 使用了引用实现,方便帮助GC 见上文
        • Album配置

          • 在resources资源文件夹下的META-INF/afterimage/AlbumProvider.def中配置,格式如:order,name,providerClass,选择时,order小的优先,可以以#开头在上一行添加注释

            • 0,SoftReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
              100,WeakReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.WeakReferenceAlbumProvider
              1000,StrongReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.StrongReferenceAlbumProvider
              10000,NopAlbum,cn.gov.zcy.afterimage.core.album.NopAlbumProvider
              
      • 默认实现:

        • 0,SoftReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
          • 软引用map实现,help gc
        • 100,WeakReferenceAlbum,cn.gov.zcy.afterimage.core.album.reference.WeakReferenceAlbumProvider
          • 弱引用map实现,help gc
        • 1000,DefaultAlbum,cn.gov.zcy.afterimage.core.album.reference.StrongReferenceAlbumProvider
          • map实现
        • 10000,NopAlbum,cn.gov.zcy.afterimage.core.album.NopAlbumProvider
          • 空实现
      • 只能使用一个具体实现,默认取order最小的那一个

    • 3、afterimage-captor 用来按需捕获调用结果进行存储

      • 背景知识:dubbo SPI 见上文dubbo filter的使用
      • 配置项为:afterimage.captor.dubbo.config
      • 配置格式:接口名1#方法名1=过期时间毫秒&方法名2=过期时间毫秒,接口名2#方法名1=过期时间&方法名2=过期时间
        • 可用*匹配所有方法名;过期时间单位为毫秒,当未配置或者小于1时,代表不过期,特别注意:当被优化方法执行完毕时,执行期间存储的调用将自动失效。
        • 配置eg: com.A#a=1&b&c=2,com.B#*=1
        • 目前不支持重载方法不同配置
      • AfterimageCaptorFilter实现了dubbo filter,使用代理设计模式,在调用dubbo接口前,先查询album是否有返回结果,在dubbo接口调用之后,将调用id和rpc结果放入到album中
        • 执行时机:消费方
        • **执行过程简述:**先获取dubbo配置,查询db(album)中是否存在该dubbo接口执行结果,有结果,直接返回该数据,否则,执行远程rpc调用,然后将方法入参和调用结果缓存到db(album)中
          • 类似于查询redis,查不到就查询db,并将结果放到redis中
      • 添加Activate注解,标识其为被代理对象,其注解含义如下
        • group :所属组:消费者,只能在消费端使用
        • order: 多个filter的执行顺序(越小越早)
        • 文件名:com.alibaba.dubbo.rpc.Filter 对于Filter的接口
      • 执行过程详述: 在resources目录下新建META-INF文件夹,然后建立子文件夹dubbo,最后新建文件com.alibaba.dubbo.rpc.Filter --》key为过滤器的实例名,value为过滤器的全类名 --》在dubbo接口执行之前,会进入拦截器里面 --》
        • 在拦截器里面 --》先获取CompositeConfig配置,如果配置项不存在或者开关未开启,提前return --》否则,获取配置项,优先上下文配置,获取dubbo接口全路径,不存在的话,获取Config中的数据 --》读取配置项,入参为原始配置 + dubbo执行信息,在工具类里面获取dubboConfig --》获取超期时间 --》如果获取的配置为空,执行invoke方法调用远程rpc,否则获取上下文,然后生成调用id --》获取应用程序信息,group信息,版本信息,接口名和方法名,入参类型信息(用逗号链接),入参信息(用逗号链接) --》使用 + 将上述全部信息连接后返回 --》获取db数据(album),由上下文+dubbo信息查询album中是否存在数据,如果为空,返回null,否则 --》判断是否有设置超期时间,如果没有设置,返回album对应的值,–》如果已经超期了,从album中删除数据,否则,返回album对应的值 --》有值,说明近期有调用,AsyncRpcResult返回该值,否则,没有结果
        • 执行rpc调用,拿到返回结果,如果返回结果没有异常,将结果写入到album中,入参为上下文id,dubbo组装参数后的id,rpc调用的结果,超期时间 --》album如果没有key,初始化,然后以dubbo组装参数后的id为key,rpc结果,超期时间,当前时间这三个字段组装的对象为value,存入map中
        • 如果这个过程中发生了异常,分类讨论,如果执行了远程rpc,并且结果非空,返回执行结果,结果为空,抛出异常 --》没有执行远程rpc,此时调用远程rpc接口,并返回
        • Action:这个兜底逻辑中,执行远程rpc后,没有把执行结构放入到album中
    • 4、afterimage-boot 启动afterimage

      • 实现了切面逻辑 ,源码分析如下
      • 注入切面的逻辑
    • 5、afterimage-core 核心类,

      • 定义了spi拓展接口:
        • cn.gov.zcy.afterimage.core.config.Config:可用于配置读取、监听的扩展
        • cn.gov.zcy.afterimage.core.album.Album:用于存储调用结果
    • 6、afterimage-boot-dubbo模块

      • AfterimageBootFilter实现了dubbo filter,使用代理设计模式,在调用dubbo接口前,先查询album是否有返回结果,在dubbo接口调用之后,将调用id和rpc结果放入到album中
        • 执行时机:生产方
        • 执行过程简述: 先获取dubbo配置,查询Config中配置是否开启,没开启,执行远程rpc,否则,查询配置项,有方法入参查询超期时间,配置超期时间,执行rpc调用,最后清理db(album) 数据
          • 可以类似于redis中:缓存时间到期了,清理redis缓存
          • Action:这个操作不优雅,它是在每次调用dubbo接口时,判断当前执行的方法有没有过期,可以模仿redis删除key的实现思路
      • 添加Activate注解,标识其为被代理对象,其注解含义如下
        • group :所属组:提供者,只能在服务提供端使用
      • 前提:需要引入对应captor才会优化相应的调用
        • 配置项为:afterimage.boot.dubbo.config
        • 配置格式:接口名1#方法名1=过期时间毫秒&方法名2=过期时间毫秒,接口名2#方法名1&方法名2=过期时间
          • 可用 * 匹配所有方法名;过期时间单位为毫秒,当未配置或者小于1时,代表不过期,特别注意:当被优化方法执行完毕时,执行期间存储的调用将自动失效。
          • 配置eg: com.A#a=1&b&c=2,com.B#*=1
        • 目前不支持重载方法不同配置
      • 在resources目录下新建META-INF文件夹,然后建立子文件夹dubbo,最后新建文件com.alibaba.dubbo.rpc.Filter --》key为过滤器的实例名,value为过滤器的全类名
        • 在服务提供端接口返回之前,会进入拦截器里面 --》首先获取CompositeConfig配置,如果配置项不存在或者开关未开启,执行dubbo接口invoke业务逻辑 --》否则,获取配置项详情,原始配置 格式如:接口名#方法名=过期时间&方法名=过期时间,接口名#方法名=过期时间&方法名=过期时间 --》获取配置详情,如果为空,跳过,否则 --》去除全部空格,接口的配置用’,'隔开,接口名和方法使用“#”分割,如果不合规范,跳过 --》如果当前的接口名与入参接口名相符,继续匹配方法的参数,使用“&”分割,然后使用 “=” 分割入参的key和value,如果key value不是一个pair,跳过,否则,获取入参的key --》如果key为通配符“*” 或者符合入参方法名,执行DubboConfig方法 --》设置超期时间,目前只有expireMills一个配置项,返回DubboConfig —》如果获取到的DubboConfig对象为null,执行dubbo业务逻辑并返回,否则 --》调用startAfterimageManage,底层为AfterimageManage的start1方法,入参为超期时间 --》然后执行dubbo invoke执行业务方法 --》最后,调用AfterimageManage的end方法清理数据
        • Action:这个过滤器如果执行报错,不需要补偿吗?
    • 残影系统使用的设计模式:

      • 1、代理模式 在dubbo invoke之前和之后执行某些操作
      • 2、filter模式:拦截器设计模式
  • 源码分析:

    • 入口:切面AfterimageAspectj

    • 在构造器里面初始化,如果已经初始化,提前return,否则,调用AfterimageManage初始化数据 --》对ConfigLoader进行初始化 --》对AlbumLoader进行初始化 --》环切操作,先判断ConfigLoader中“afterimage.spring.enabled”配置项是否打开,如果没有打开,直接执行业务逻辑,否则 --》调用start0开始执行切面逻辑,然后执行业务逻辑,最后执行残影的清理操作(end方法)

    • AfterimageManage --》初始化init,如果已经初始化,return,否则 --》初始化项目,

      • ConfigLoader

        • order_key:afterimage.config.order
        • PATH = “META-INF/afterimage/ConfigProvider.def” 使用系统配置
          • order:1000
          • name:SystemConfig
          • providerClassName:cn.gov.zcy.afterimage.core.config.SystemConfigProvider
        • CompositeConfig CONFIG
        • 初始化,如果CONFIG非空,说明已经被初始化了,提前return --》 由固定的PATH查询Spi order_key拓展信息 --》加载资源,由path获取类加载器中的urls,–》如果加载出的资源为空,return,否则 --》解析路径,如果路径长度不等于3,抛出异常,否则 --》定义SpiModel,并组装顺序、名称、类名 --》按顺序排序 --》定义组合配置CompositeConfig,将SpiModel转换为CompositeConfig --》按key为name,value为spiModel构建为map --》指定顺序排序(afterimage–config–order) --》循环遍历SpiModel,通过类名获取类实例,然后添加到配置中
      • AlbumLoader

        • ALBUM_KEY = “afterimage.album”
        • PATH = “META-INF/afterimage/AlbumProvider.def”
        • ALBUM
        • List < SpiModel> SPI_MODELS
          • order :0
          • name:SoftReferenceAlbum
          • providerClassName:cn.gov.zcy.afterimage.core.album.reference.SoftReferenceAlbumProvider
        • 初始化 --》如果CONFIG非空,说明已经被初始化了,提前return --》 由固定的PATH查询Spi拓展信息 --》加载资源,由path获取类加载器中的urls,–》如果加载出的资源为空,return,否则 --》解析路径,如果路径长度不等于3,抛出异常,否则 --》定义SpiModel,并组装顺序、名称、类名 --》按顺序排序 --》按key为name,value为spiModel构建为map --》指定顺序排序(afterimage–config–order) --》循环遍历SpiModel,通过类名获取类实例,然后添加到配置中
          • 加载:–》获取SPI_MODELS的第一条数据, --》如果指定了CompositeConfig,使用指定的,否则 --》调用ConfigLoader初始化接口,返回CONFIG --》从配置项中读取“afterimage.album”,使用指定的spiModel --》获取单签拓展点实例信息 --》添加钩子函数,在程序结束时自动销毁album
      • 强制清除方法 forceClear --》获取残影上下文,如果为空,提前return,否则 --》由AlbumLoader获取ALBUM,做清理工作 --》然后由残影上下文中移除ThreadLocal数据

      • start0

        • 执行时机

          • 当进入切面后
        • 业务逻辑:

          • 当某线程连续调用start时,只有第一次的配置生效 --》入参为残影注解,如果没有配置过期时间,返回null --》入参中的captor非空,循环遍历captorConfig --》组装captor(目前仅为dubbo接口),config(dubbo接口的全路径)–》组装到配置项AfterimageConfig中 --》然后调用start(afterimageConfig)方法执行后续逻辑 --》

          • 当嵌套多次start时,计数器会加1,调用end是减1,当为0时,代表上下文安全结束 --》判断是否是新的上下文,如果通过Local能获取上下文,返回该数据,否则 --》 创建一个空的上下文到Local中,返回Local --》计数器自增,如果计数器值不为1,返回false,否则,将入参中的配置放入上下文中,然后返回true

      • start1

        • 执行时机

          • 对于每一个执行的dubbo,都会进入拦截器里面去,然后判断有没有匹配上,有配置上,重新计算超期时间
        • 业务逻辑

          • 当某线程连续调用start时,只有第一次的配置生效 --》过期时间毫秒-为null或小于1,将不过期 --》获取Local里面的上下文,如果数据非空,返回上下文,否则 --》初始化Local后返回 --》计数器自增,如果计数器不为1,返回false,否则,组装配置后,返回true
        • Action:计数器起的作用是啥? 返回的true,false是啥意思?

          • 计数器是为空防止一次请求中,进入切面里面多次
        • Action:提供的两filter方法会拦截全部的dubbo接口,这样做不会影响性能吗?

      • start(expireMills, captorConfigList) 当某线程连续调用start时,只有第一次的配置生效

      • end 在结束后必须调用end --》获取Local中的上下文,如果上下文为空,抛错异常,否则 --》计数器自减 --》如果数量不为0,返回false,标识在其它上下文之中,不用清理数据,否则 --》返回true,获取Album,做清理操作,清理上下文信息,return

    • SystemConfigProvider 系统配置提供方

    • SoftReferenceAlbumProvider

3、SPI总结

1、利用Dubbo SPI机制提供的良好拓展性

  • 1、整个框架中针对不同的场景,恰到好处地使用了各种设计模式
  • 2、基于Dubbo SPI 加载机制,让整个框架的接口和具体实现完全解耦合

2、缓存思想的运用

  • 先获取dubbo配置,查询db(album)中是否存在该dubbo接口执行结果,有结果,直接返回该数据,否则,执行远程rpc调用,然后将方法入参和调用结果缓存到db(album)中
  • 先获取dubbo配置,查询Config中配置是否开启,没开启,执行远程rpc,否则,查询配置项,有方法入参查询超期时间,配置超期时间,执行rpc调用,最后清理db(album) 数据

你可能感兴趣的:(深入理解服务中间件,dubbo,SPI,Filter,自定义注解)