1. 程式人生 > >Dubbo SPI介紹

Dubbo SPI介紹

為什麼要設計adaptive?註解在類上和註解在方法上的區別?
adaptive設計的目的是為了識別固定已知類和擴充套件未知類。
1.註解在類上:代表人工實現,實現一個裝飾類(設計模式中的裝飾模式),它主要作用於固定已知類,
  目前整個系統只有2個,AdaptiveCompiler、AdaptiveExtensionFactory。
  a.為什麼AdaptiveCompiler這個類是固定已知的?因為整個框架僅支援Javassist和JdkCompiler。
  b.為什麼AdaptiveExtensionFactory這個類是固定已知的?因為整個框架僅支援2個objFactory,一個是spi,另一個是spring
2.註解在方法上:代表自動生成和編譯一個動態的Adpative類,它主要是用於SPI,因為spi的類是不固定、未知的擴充套件類,所以設計了動態$Adaptive類.
例如 Protocol的spi類有 injvm dubbo registry filter listener等等 很多擴充套件未知類,
它設計了Protocol$Adaptive的類,通過ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi類);來提取物件


為什麼dubbo要自己設計一套SPI?
這是原始JDK spi的程式碼
    ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class); 
  for(Command command:serviceLoader){  
      command.execute();  
  }  
dubbo在原來的基礎上設計了以下功能
1.原始JDK spi不支援快取;dubbo設計了快取物件:spi的key與value 快取在 cachedInstances物件裡面,它是一個ConcurrentMap
2.原始JDK spi不支援預設值,dubbo設計預設值:@SPI("dubbo") 代表預設的spi物件,例如Protocol的@SPI("dubbo")就是 DubboProtocol,
  通過 ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension()那預設物件
3.jdk要用for迴圈判斷物件,dubbo設計getExtension靈活方便,動態獲取spi物件,
  例如 ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi的key)來提取物件
4.原始JDK spi不支援 AOP功能,dubbo設計增加了AOP功能,在cachedWrapperClasses,在原始spi類,包裝了XxxxFilterWrapper XxxxListenerWrapper
5.原始JDK spi不支援 IOC功能,dubbo設計增加了IOC,通過建構函式注入,程式碼為:wrapperClass.getConstructor(type).newInstance(instance),

dubbo spi 的目的:獲取一個指定實現類的物件。
途徑:ExtensionLoader.getExtension(String name)
實現路徑:
getExtensionLoader(Class<T> type) 就是為該介面new 一個ExtensionLoader,然後快取起來。
getAdaptiveExtension() 獲取一個擴充套件類,如果@Adaptive註解在類上就是一個裝飾類;如果註解在方法上就是一個動態代理類,例如Protocol$Adaptive物件。
getExtension(String name) 獲取一個指定物件。


-----------------------ExtensionLoader.getExtensionLoader(Class<T> type)
ExtensionLoader.getExtensionLoader(Container.class)
  -->this.type = type;
  -->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
     -->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
       -->this.type = type;
       -->objectFactory =null;
       
執行以上程式碼完成了2個屬性的初始化
1.每個一個ExtensionLoader都包含了2個值 type 和 objectFactory
  Class<?> type;//構造器  初始化時要得到的介面名
  ExtensionFactory objectFactory//構造器  初始化時 AdaptiveExtensionFactory[SpiExtensionFactory,SpringExtensionFactory]
2.new 一個ExtensionLoader 儲存在ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS

關於這個objectFactory的一些細節:
1.objectFactory就是ExtensionFactory,它也是通過ExtensionLoader.getExtensionLoader(ExtensionFactory.class)來實現的,但是它的objectFactory=null
2.objectFactory作用,它就是為dubbo的IOC提供所有物件。
       

-----------------------getAdaptiveExtension()


-->getAdaptiveExtension()//為cachedAdaptiveInstance賦值
  -->createAdaptiveExtension()
    -->getAdaptiveExtensionClass()
      -->getExtensionClasses()//為cachedClasses 賦值
        -->loadExtensionClasses()
          -->loadFile
      -->createAdaptiveExtensionClass()//自動生成和編譯一個動態的adpative類,這個類是一個代理類
        -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension()
        -->compiler.compile(code, classLoader)
    -->injectExtension()//作用:進入IOC的反轉控制模式,實現了動態入注
        
          
關於loadfile的一些細節
目的:通過把配置檔案META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol的內容,儲存在快取變數裡面。
cachedAdaptiveClass//如果這個class含有adative註解就賦值,例如ExtensionFactory,而例如Protocol在這個環節是沒有的。
cachedWrapperClasses//只有當該class無adative註解,並且建構函式包含目標介面(type)型別,
                                                                 例如protocol裡面的spi就只有ProtocolFilterWrapper和ProtocolListenerWrapper能命中
cachedActivates//剩下的類,包含Activate註解
cachedNames//剩下的類就儲存在這裡。

-----------------------getExtension(String name)
getExtension(String name) //指定物件快取在cachedInstances;get出來的物件wrapper物件,例如protocol就是ProtocolFilterWrapper和ProtocolListenerWrapper其中一個。
  -->createExtension(String name)
    -->getExtensionClasses()
    -->injectExtension(T instance)//dubbo的IOC反轉控制,就是從spi和spring裡面提取物件賦值。
      -->objectFactory.getExtension(pt, property)
        -->SpiExtensionFactory.getExtension(type, name)
          -->ExtensionLoader.getExtensionLoader(type)
          -->loader.getAdaptiveExtension()
        -->SpringExtensionFactory.getExtension(type, name)
          -->context.getBean(name)
    -->injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//AOP的簡單設計