dubbo SPI的实现过程

叁歲伎倆 2023-10-11 12:47 94阅读 0赞
  1. 问题

    dubbo的自适应类加载机制是如何实现的? 例如,Protocol的实现类是如何加载的

    // 如何解析

    1. private static final Protocol REF_PROTOCOL = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    1. 解析过程

      getAdaptiveExtension() —-> createAdaptiveExtension()—->

      getAdaptiveExtensionClass()—->

      getExtensionClasses()—->

      loadExtensionClasses()

      createAdaptiveExtensionClass()—->

      private Class<?> createAdaptiveExtensionClass() {

      1. String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
      2. ClassLoader classLoader = findClassLoader();
      3. Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
      4. return compiler.compile(code, classLoader);

      }

    获取dubbo.jar的META-INF/dubbo目录下指定的文件

    private Map> loadExtensionClasses() {

    1. this.cacheDefaultExtensionName();
    2. Map<String, Class<?>> extensionClasses = new HashMap();
    3. this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName());
    4. this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName().replace("org.apache", "com.alibaba"));
    5. this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName());
    6. this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName().replace("org.apache", "com.alibaba"));
    7. this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName());
    8. this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName().replace("org.apache", "com.alibaba"));
    9. return extensionClasses;
    10. }

获取接口定义信息中的默认扩展名

  1. private void cacheDefaultExtensionName() {
  2. SPI defaultAnnotation = (SPI)this.type.getAnnotation(SPI.class);
  3. if (defaultAnnotation != null) {
  4. String value = defaultAnnotation.value();
  5. if ((value = value.trim()).length() > 0) {
  6. String[] names = NAME_SEPARATOR.split(value);
  7. if (names.length > 1) {
  8. throw new IllegalStateException("More than 1 default extension name on extension " + this.type.getName() + ": " + Arrays.toString(names));
  9. }
  10. if (names.length == 1) {
  11. this.cachedDefaultName = names[0];
  12. }
  13. }
  14. }
  15. }

默认选择的实现类

  1. @SPI("dubbo")
  2. public interface Protocol {
  3. int getDefaultPort();
  4. @Adaptive
  5. <T> Exporter<T> export(Invoker<T> var1) throws RpcException;
  6. @Adaptive
  7. <T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;
  8. void destroy();
  9. }

自动生成的DubboProtocol代码

动态生成代码

  1. StringBuilder code = new StringBuilder();
  2. code.append(this.generatePackageInfo()); // 包名
  3. code.append(this.generateImports()); // import
  4. code.append(this.generateClassDeclaration()); // 类定义
  5. Method[] methods = this.type.getMethods(); // 方法,来自接口的定义,实现这些接口
  6. Method[] var3 = methods;
  7. int var4 = methods.length;
  8. for(int var5 = 0; var5 < var4; ++var5) {
  9. Method method = var3[var5];
  10. code.append(this.generateMethod(method)); // 方法的实现
  11. }
  12. private String generateMethod(Method method) {
  13. String methodReturnType = method.getReturnType().getCanonicalName();
  14. String methodName = method.getName();
  15. String methodContent = this.generateMethodContent(method);
  16. String methodArgs = this.generateMethodArguments(method);
  17. String methodThrows = this.generateMethodThrows(method);
  18. return String.format("public %s %s(%s) %s {\n%s}\n", methodReturnType, methodName, methodArgs, methodThrows, methodContent);
  19. }

最终生成的代码如下:

  1. package org.apache.dubbo.rpc;
  2. import org.apache.dubbo.common.extension.ExtensionLoader;
  3. public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
  4. public void destroy() {
  5. throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
  6. }
  7. public int getDefaultPort() {
  8. throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
  9. }
  10. public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
  11. if (arg1 == null) throw new IllegalArgumentException("url == null");
  12. org.apache.dubbo.common.URL url = arg1;
  13. String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
  14. if (extName == null)
  15. throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
  16. org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
  17. return extension.refer(arg0, arg1);
  18. }
  19. public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
  20. if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
  21. if (arg0.getUrl() == null)
  22. throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
  23. org.apache.dubbo.common.URL url = arg0.getUrl();
  24. String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
  25. if (extName == null)
  26. throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
  27. org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
  28. return extension.export(arg0);
  29. }
  30. }
  31. org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
  32. public T getExtension(String name) {
  33. if (StringUtils.isEmpty(name)) {
  34. throw new IllegalArgumentException("Extension name == null");
  35. } else if ("true".equals(name)) {
  36. return this.getDefaultExtension();
  37. } else {
  38. Holder<Object> holder = this.getOrCreateHolder(name);
  39. Object instance = holder.get();
  40. if (instance == null) {
  41. synchronized(holder) {
  42. instance = holder.get();
  43. if (instance == null) {
  44. instance = this.createExtension(name);
  45. holder.set(instance);
  46. }
  47. }
  48. }
  49. return instance;
  50. }
  51. }
  52. private T createExtension(String name) {
  53. Class<?> clazz = (Class)this.getExtensionClasses().get(name); // 加载META-INF/dubbo
  54. if (clazz == null) {
  55. throw this.findException(name);
  56. } else {
  57. try {
  58. T instance = EXTENSION_INSTANCES.get(clazz);
  59. if (instance == null) {
  60. EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); // 实例化
  61. instance = EXTENSION_INSTANCES.get(clazz);
  62. }

发表评论

表情:
评论列表 (有 0 条评论,94人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Dubbo SPI

    前言 前面已经讲过[JDK SPI][], dubbo SPI主要基于JDK SPI机制,进行了增强,实现可扩展 为什么不直接用JDK的SPI呢,主要有哪些改变