Dubbo学习 ExtensionLoader.getExtensionLoader解析

在使用dubbo的SPI 的时候,必不可少的就是扩展点加载器ExtensionLoader;
现在来学习了解一下它的机制

 ExtensionLoader<TodayService> loader = ExtensionLoader.getExtensionLoader(TodayService.class);
  1. org.apache.dubbo.common.extension.ExtensionLoader#getExtensionLoader
  private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

  public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  		// 首先第一步 对参数进行校验
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }
        if (!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type +
                    ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
        }
        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;
    }

首先 会去校验参数,然后从缓存EXTENSION_LOADERS 中获取,EXTENSION_LOADERS 是一个ConcurrentHashMap; 设计缓存是为了防止重复创建; 如果缓存中没有就调用new ExtensionLoader(type) 创建

  1. org.apache.dubbo.common.extension.ExtensionLoader#ExtensionLoader
  private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

可以看到构造方法会去获取ExtensionFactory的Adaptive扩展点加载器
3. org.apache.dubbo.common.extension.ExtensionLoader#getAdaptiveExtension

 public T getAdaptiveExtension() {
 	    // 从缓存中获取AdaptiveExtension
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }
            //双重检查锁
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 实例化AdaptiveExtension
                        instance = createAdaptiveExtension();
                        // 放入缓存
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }
public class Holder<T> {

    private volatile T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

}

可以看到会先去cachedAdaptiveInstance缓存中获取实例,这里的缓存是个Holder,应为只会有一个AdaptiveExtension ;获取不到就会去创建ExtensionFactory的AdaptiveExtension

  1. org.apache.dubbo.common.extension.ExtensionLoader#createAdaptiveExtension
private T createAdaptiveExtension() {
        try {
        // getAdaptiveExtensionClass: 获取AdaptiveExtensionFactory 并实例化
        // injectExtension 注入
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
  1. org.apache.dubbo.common.extension.ExtensionLoader#getAdaptiveExtensionClass
    private Class<?> getAdaptiveExtensionClass() {
    // 获取AdaptiveExtensionFactory的class 
        getExtensionClasses();
        // 如果 缓存cachedAdaptiveClass不为空直接返回,否则创建
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
  1. org.apache.dubbo.common.extension.ExtensionLoader#getExtensionClasses
private Map<String, Class<?>> getExtensionClasses() {
      //从缓存中获取
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
           // 双重检查锁
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                 // 加载class
                    classes = loadExtensionClasses();
                    //放入缓存
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
  1. org.apache.dubbo.common.extension.ExtensionLoader#loadExtensionClasses
 private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // internal extension load from ExtensionLoader's ClassLoader first
        //META-INF/dubbo/internal/
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName(), true);
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"), true);
        //META-INF/dubbo
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        return extensionClasses;
    }

META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory

spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
  1. org.apache.dubbo.common.extension.ExtensionLoader#loadDirectory(java.util.Map<java.lang.String,java.lang.Class<?>>, java.lang.String, java.lang.String, boolean)
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst) {
        //META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory
        // 目录加+type
        String fileName = dir + type;
        try {
            Enumeration<java.net.URL> urls = null;
            // 获取类加载器
            ClassLoader classLoader = findClassLoader();
            
            // try to load from ExtensionLoader's ClassLoader first
            if (extensionLoaderClassLoaderFirst) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                    urls = extensionLoaderClassLoader.getResources(fileName);
                }
            }
            // 生成urls
            if(urls == null || !urls.hasMoreElements()) {
                if (classLoader != null) {
                    urls = classLoader.getResources(fileName);
                } else {
                    urls = ClassLoader.getSystemResources(fileName);
                }
            }

            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL resourceURL = urls.nextElement();
                    // 根据类加载器和url 对扩展点进行加载
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }
  1. org.apache.dubbo.common.extension.ExtensionLoader#loadResource
 private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            // 根据url 读取文件
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
            // 解析文件内容
                String line;
                while ((line = reader.readLine()) != null) {
                    final int ci = line.indexOf('#');
                    if (ci >= 0) {
                        line = line.substring(0, ci);
                    }
                    line = line.trim();
                    if (line.length() > 0) {
                        try {
                            String name = null;
                            int i = line.indexOf('=');
                            if (i > 0) {
                                // key
                                name = line.substring(0, i).trim();
                                //value
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                               // 获取扩展点的class	
                                loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable t) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                            exceptions.put(line, e);
                        }
                    }
                }
            }
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }
  1. org.apache.dubbo.common.extension.ExtensionLoader#loadClass
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
		// 校验参数
        if (!type.isAssignableFrom(clazz)) {
            throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + " is not subtype of interface.");
        }
        // 是否有Adaptive注解 我们可以看到AdaptiveExtensionFactory 类上有@Adaptive
        if (clazz.isAnnotationPresent(Adaptive.class)) {
           // 进行缓存 赋值给cachedAdaptiveClass
            cacheAdaptiveClass(clazz);
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }

            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n);
                }
            }
        }
    }

这里我们获取到了AdaptiveExtensionFactory,然后返回到第4步,对AdaptiveExtensionFactory进行实例化
4.1 org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory#AdaptiveExtensionFactory

public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        // 获取ExtensionFactory的扩展点加载器
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        //getSupportedExtensions 获取当前类型所支持的扩展点
        // 进行遍历加载
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    @Override
    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;
    }

}

4.2 org.apache.dubbo.common.extension.ExtensionLoader#getSupportedExtensions

public Set<String> getSupportedExtensions() {
       // spring -> class org.apache.dubbo.config.spring.extension.SpringExtensionFactory
       // spi -> class org.apache.dubbo.common.extension.factory.SpiExtensionFactory
        Map<String, Class<?>> clazzes = getExtensionClasses();
        return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
    }

4.3 org.apache.dubbo.common.extension.ExtensionLoader#getExtension

 public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        final Holder<Object> holder = getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                     // 如果从缓存中获取不到就进行实例化
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

以上就是获取 ExtensionLoader 的基本流程

  • ExtensionLoader被设计成单例模式 什么时候用单例模式呢
    对象具有唯一性,创建是比较耗资源可以考虑;比如本案例,创建ExtensionLoader< T > 获取读取文件

  • 什么时候要去用本地缓存EXTENSION_LOADERS ,cachedAdaptiveInstance,cachedClasses,holder 呢
    最大程度是避免重复加载,如最大程度上避免直接访问数据库

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值