Dubbo SPI

在前面的学习中ServiceConfig中有一段

private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

点击进入Protocol ,可以看到一个特殊的注解@SPI。学习一下:
java spi机制
SPI,Service Provider Interface,主要是被框架的开发人员使用,比如java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,mysql和postgresql都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。
spi 经典的思想体现,大家平时都在用,比如说 jdbc。
Java 定义了一套 jdbc 的接口,但是 Java 并没有提供 jdbc 的实现类。
但是实际上项目跑的时候,要使用 jdbc 接口的哪些实现类呢?一般来说,我们要根据自己使用的数据库,比如 mysql,你就将 mysql-jdbc-connector.jar 引入进来;oracle,你就将 oracle-jdbc-connector.jar 引入进来。
在系统跑的时候,碰到你使用 jdbc 的接口,他会在底层使用你引入的那个 jar 中提供的实现类。

回到上面的问题:
Protocol 接口,在系统运行的时候,,dubbo 会判断一下应该选用这个 Protocol 接口的哪个实现类来实例化对象来使用。
它会去找一个你配置的 Protocol,将你配置的 Protocol 实现类,加载到 jvm 中来,然后实例化对象,就用你的那个 Protocol 实现类就可以了。
spi机制有几个重要的注解:

1、@SPI注解,被此注解标记的接口,就表示是一个可扩展的接口,并标注默认值。
2、@Adaptive注解,有两种注解方式:一种是注解在类上,一种是注解在方法上。
3、@Activate注解,此注解需要注解在类上或者方法上,并注明被激活的条件,以及所有的被激活实现类中的排序信息

接下来继续看代码,可以看到Protocol的spi的默认值是dubbo,这个在初始化类的时候很有用,假如你的Protocol实现类有很多,在dubbo中就有如下实现类:

@SPI("dubbo")
public interface Protocol {
    int getDefaultPort();

    @Adaptive
    <T> Exporter<T> export(Invoker<T> var1) throws RpcException;

    @Adaptive
    <T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;

    void destroy();
}

java中proxy类 provider java_java


@Adaptive注解:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})  //只能注解在类、接口、方法上面
public @interface Adaptive {

    String[] value() default {};

}

@adaptive注解在类上面:AdaptiveExtensionFactory @adaptive注解在方法上面:Protocol

注解在类上:代表人工实现编码,即实现了一个装饰类(设计模式中的装饰模式),例如:ExtensionFactory
注解在方法上:代表自动生成和编译一个动态的adpative类,例如:Protocol$adpative

dubbo对于SPI的实现主要是在ExtensionLoader这个类中,这个类主要有三个方法:

getExtension():主要用于获取名称为name的对应的子类的对象,这里如果子类对象如果有AOP相关的配置,这里也会对其进行封装;
getAdaptiveExtension():使用定义的装饰类来封装目标子类,具体使用哪个子类可以在定义的装饰类中通过一定的条件进行配置;
getExtensionLoader():加载当前接口的子类并且实例化一个ExtensionLoader对象。

public T getExtension(String name);
public T getAdaptiveExtension();
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type);

具体学习内容可以参考:https://www.jianshu.com/p/0ee6e2455e02

-----------------------getAdaptiveExtension()
 -->getAdaptiveExtension()   //目的为  cachedAdaptiveInstance赋值
   -->createAdaptiveExtension()
     -->getAdaptiveExtension()
       -->getExtensionClasses()   //目的为cachedClasses赋值
         -->loadExtensionClasses()  //加载
           -->loadFile()  //加载配置信息(主要是META_INF/services/下)
      -->createAdaptiveExtensionClass() //自动生成和编译一个动态的adpative类,这个类是个代理类
        -->createAdaptiveExtensionClassCode()//通过adaptive模板生成代码
          -->ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();//编译
          -->compile(String code, ClassLoader classLoader)
       -->injectExtension()//作用:进入IOC的反转控制模式,实现了动态入注

对我来说这些还有点难。。未完待续。。