Dubbo-SPI

本文详细介绍了Java的SPI(Service Provider Interface)机制,包括定义、约定和示例,并探讨了Dubbo如何基于SPI思想进行增强,强调了Dubbo SPI在资源管理、依赖注入和扩展点查找流程上的优化。同时,详细解析了Dubbo SPI接口定义、ExtensionLoader的工作原理及加载流程。
摘要由CSDN通过智能技术生成

SPI

1. 定义

SPI即Service Provider Interface,服务提供接口。

​ 系统中抽象的各个模块,往往有很多不同的实现方案,比如日志模块,xml解析模块,jdbc模块的方案等。面向对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里设计具体的实现类,就违反了可插拔的原则,如果需要替换一种实现,就需要修改代码。

​ 为了实现在模块装配的时候能不在程序里动态指明,就需要一种服务发现机制。JAVA SPI就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将转配的控制权一到程序之外,在模块化设计中这个机制尤其重要。

1.1. Java SPI的约定

​ 当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同事创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过jar包META-INF/services里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。

​ 基于这样一个约定就能很好的找到接口的实现类,而不需要在代码里定制。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader

1.2. 范例
1.3. Demo

定义接口类

package cn.test.spi;

public interface Animal {
  String cry();
}

接口实现类

package cn.test.spi;

public class Cat implements Animal {
    public String cry() {
        return "cat cry...";
    }
}

public class Dog implements Animal {
    public String cry() {
        return "dog cry...";
    }
}

运行

package cn.test.spi;

import java.util.Iterator;
import java.util.ServiceLoader;

public class TestAnimal {
    public static void main(String[] args) {
        ServiceLoader<Animal> loader = ServiceLoader.load(Animal.class);
        Iterator<Animal> iterator = loader.iterator();
        while (iterator.hasNext()) {
            Animal animal = iterator.next();
            System.out.println(animal.getClass());
            System.out.println(animal.cry());
        }
    }
}

其中,在META-INF/services目录中创建文件cn.test.spi.Animal,内容为cn.test.spi.Cat

输出结果为:

class cn.test.spi.Cat
cat cry...

以上及时基于Java SPI机制查找服务的实现。

2. Dubbo基于SPI思想实现

Dubbo对Java SPI发现机制加强而来。

  1. Java SPI标准的SPI会一次性实例化扩展点的所有实现,如果扩展实现很耗时,但如果没有用到也加载,会资源;还有如果实现类缺失依赖,实例化直接出错;
  2. 如果扩展点记载失败,连扩展点的名称都拿不到;
  3. 增加了IOC的支持,一个扩展点可以直接setter注入其他扩展点;

优先关注dubbo-common子项目的com.alibaba.dubbo.common.extension类包。

2.1. SPI接口定义

Dubbo定义了注解@SPI用于扩展,只要在接口上打了@SPI注解的接口才会去找找扩展点实现。

配置信息会从以下几个位置读取扩展信息:

  1. META-INF/dubbo/internal/
  2. META-INF/dubbo/
  3. META-INF/services/

com.alibaba.dubbo.rpc.ProxyFactory为例:

@SPI("javassist")
public interface ProxyFactory {

    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;

    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;

}

2.2. ExtensionLoader类解析

每个定义SPI的接口都会构建一个ExtensionLoader实例,存储在ExtensionLoader.EXTENSION_LOADERS属性中。

// 触发入口
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    // check  
    ... 
  ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  if (loader == null) {
    EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
    loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  }
  return loader;
}

// 构建ExtensionLoader对象
private ExtensionLoader(Class<?> type) {
  this.type = type;
  // 当type不是ExtensionFactory类型时,寻找ExtensionFactory对象,
  // 赋值给ExtensionLoader的objectFactory,为了之后IOC寻找依赖对象时使用;
  // 由此可以看出,如果使用dubbo的SPI,第一个初始化的就是ExtensionFactory扩展节点;
  // 下节通过动态扩展ExtensionFactory节点来了解代码运行轨迹;
  objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
2.3. 加载流程

提供由SPI扩展对象依赖属性的查找入口。

// 当clazz不是ExtensionFactory.clss,第一个调用触发ExtensionLoader<ExtensionFactory>对象初始化;
ExtensionLoader.getExtensionLoader(clazz);

private ExtensionLoader(Class<?> type) {
  this.type = type;
  // getAdaptiveExtension方法触发初始化;
  // 通过该方法获得指定类型的代理对象,并非实际的业务处理对象;
  // PS:代理对象生成:1、自建[通过@Adaptive标识];2、动态代理
  objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

// 创建动力扩展对象
private T createAdaptiveExtension() {
  try {
    // 1. getAdaptiveExtensionClass() 获取代理对象class
    // 2. 对指定代理class实例化
    // 3. 代理对象如有依赖,可从SPI上下文找到,通过setter方式植入
    return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  } catch (Exception e) {
    throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
  }
}

// 获取代理对象class
private Class<?> getAdaptiveExtensionClass() {
  // 通过配置文件获取扩展点 实现类
  getExtensionClasses();
  // 初始化时,如果有指定代理对象class,直接返回
  if (cachedAdaptiveClass != null) {
    return cachedAdaptiveClass;
  }
  // 初始化时,如果并没有指定代理对象class,运行时通过字节码方式动态生成class
  return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

// 加载扩展实现类
private Map<String, Class<?>> getExtensionClasses() {
  Map<String, Class<?>> classes = cachedClasses.get();
  if (classes == null) {
    synchronized (cachedClasses) {
      classes = cachedClasses.get();
      if (classes == null) {
        classes = loadExtensionClasses();
        cachedClasses.set(classes);
      }
    }
  }
  return classes;
}

// 加载扩展实现类
private Map<String, Class<?>> loadExtensionClasses() {
  final SPI defaultAnnotation = type.getAnnotation(SPI.class);
  if (defaultAnnotation != null) {
    String value = defaultAnnotation.value();
    if (value != null && (value = value.trim()).length() > 0) {
      String[] names = NAME_SEPARATOR.split(value);
      if (names.length > 1) {
        throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                                        + ": " + Arrays.toString(names));
      }
      if (names.length == 1) cachedDefaultName = names[0];
    }
  }
  Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();

  // 加载文件 META-INF/dubbo/internal/{type.getName()}
  loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
  // 加载文件 META-INF/dubbo/{type.getName()}
  loadFile(extensionClasses, DUBBO_DIRECTORY);
  // 加载文件 META-INF/services/{type.getName()}
  loadFile(extensionClasses, SERVICES_DIRECTORY);
  return extensionClasses;
}

// 在初始后,并没有找到指定的代理class,则动态生成;
private Class<?> createAdaptiveExtensionClass() {
  // 生成class的string值
  String code = createAdaptiveExtensionClassCode();
  ClassLoader classLoader = findClassLoader();
  // 获取Compiler对象
  com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  // 将生成的code,以及compiler,加载
  return compiler.compile(code, classLoader);
}

从下面截图可以获悉:Compiler的扩展类有三个,分别为:com.alibaba.dubbo.common.compiler.support.AdaptiveCompilercom.alibaba.dubbo.common.compiler.support.JdkCompilercom.alibaba.dubbo.common.compiler.support.JavassistCompiler。其中代理类为:AdaptiveCompiler

实际执行轨迹为:由于属性name为空,会通过loader.getDefaultExtension(),获取默认的扩展实现类。

public T getDefaultExtension() {
  getExtensionClasses();
  // 获取默认的扩展实现的名字, 而默认扩展实现的名字有getExtensionClasses()方法执行获得;
  if (null == cachedDefaultName || cachedDefaultName.length() == 0
      || "true".equals(cachedDefaultName)) {
    return null;
  }
  return getExtension(cachedDefaultName);
}

private Map<String, Class<?>> getExtensionClasses() {
  Map<String, Class<?>> classes = cachedClasses.get();
  if (classes == null) {
    synchronized (cachedClasses) {
      classes = cachedClasses.get();
      if (classes == null) {
        classes = loadExtensionClasses();
        cachedClasses.set(classes);
      }
    }
  }
  return classes;
}

// 此方法已经getExtensionClasses方法同步过。
private Map<String, Class<?>> loadExtensionClasses() {
  // 从SPI标签的value获取
  final SPI defaultAnnotation = type.getAnnotation(SPI.class);
  if (defaultAnnotation != null) {
    String value = defaultAnnotation.value();
    if (value != null && (value = value.trim()).length() > 0) {
      String[] names = NAME_SEPARATOR.split(value);
      if (names.length > 1) {
        throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
                                        + ": " + Arrays.toString(names));
      }
      if (names.length == 1) cachedDefaultName = names[0];
    }
  }
... // 代码省略
}

// Compiler的接口代码如下:
// 因此,Dubbo默认使用javasisist字节码类库
@SPI("javassist")
public interface Compiler {
    Class<?> compile(String code, ClassLoader classLoader);
}
2.4. IOC

动态注入属性值

injectExtension两个地方调用:

  1. createExtension(String name)
  2. createAdaptiveExtension()
private T injectExtension(T instance) {
  try {
    // objectFacatory 为ExtensionFactory的代理对象;即:AdaptiveExtensionFactory
    if (objectFactory != null) {
      for (Method method : instance.getClass().getMethods()) {
        // 通过set方法动态注入属性
        if (method.getName().startsWith("set")
            && method.getParameterTypes().length == 1
            && Modifier.isPublic(method.getModifiers())) {
          Class<?> pt = method.getParameterTypes()[0];
          try {
            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
            // 通过objectFacatory的getExtension获取属性值;
            Object object = objectFactory.getExtension(pt, property);
            if (object != null) {
              // set属性值
              method.invoke(instance, object);
            }
          } catch (Exception e) {
            logger.error("fail to inject via method " + method.getName()
                         + " of interface " + type.getName() + ": " + e.getMessage(), e);
          }
        }
      }
    }
  } catch (Exception e) {
    logger.error(e.getMessage(), e);
  }
  return instance;
}

下面看下AdaptiveExtensionFactory处理逻辑:

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
      //实例化AdaptiveExtensionFactory时候,会将所有的扩展点对象放入factories属性中;
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    // 查找执行上下文对象的时候,会按照放入factories对象的顺序;
    // 以此从扩展点对象获取,直至找到位置;
    public <T> T getExtension(Class<T> type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值