1.读dubbo spi机制源码

首先从获取拓展加载器说起

    @Override
    @SuppressWarnings("unchecked")
    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        checkDestroyed();
        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() + "!");
        }

        // 1. find in local cache
        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);

        ExtensionScope scope = extensionScopeMap.get(type);
        if (scope == null) {
            SPI annotation = type.getAnnotation(SPI.class);
            scope = annotation.scope();
            extensionScopeMap.put(type, scope);
        }

        if (loader == null && scope == ExtensionScope.SELF) {
            // create an instance in self scope
            loader = createExtensionLoader0(type);
        }

        // 2. find in parent
        if (loader == null) {
            if (this.parent != null) {
                loader = this.parent.getExtensionLoader(type);
            }
        }

        // 3. create it
        if (loader == null) {
            loader = createExtensionLoader(type);
        }

        return loader;
    }

①首先去当前对象的extensionLoadersMap(ConcurrentHashMap)属性成员中获取是否有对应type Class类的加载器
②再到当前对象的extensionScopeMap(ConcurrentHashMap)属性成员中获取对应type Class的Spi注解scope属性范围
③如果没有,就去获取type Class上面的SPI注解
④拿到SPI注解中Scope的值(默认是ExtensionScope.APPLICATION)
⑤存入当前对象的extensionScopeMap(ConcurrentHashMap)属性成员中
⑥如果第①步拿到的成员是空,且第②步拿到的scope是self,则创建一个self的loader
⑦如果scope属性值不是self且属性成员parent不为空,那么到parent中取获取加载器
⑧如果还获取不到,那么开始创建loader

这里我们重点跟踪下第⑧部的默认创建loader步骤

    private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
        ExtensionLoader<T> loader = null;
        if (isScopeMatched(type)) {
            // if scope is matched, just create it
            loader = createExtensionLoader0(type);
        }
        return loader;
    }

①检查下type Class上面的SPI注解里面的scope默认值是否和传进来的一致
②如果scope匹配,则开始创建

    private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {
        checkDestroyed();
        ExtensionLoader<T> loader;
        // ①直接通过new 一个ExtensionLoader对象(这里就会进行这个对象的一些初始化操作了,后续一些用到的属性都是在这个初始化操作完成的,我们后面遇到再重点提起)
        // ②存入当前对象成员属性extensionLoadersMap
        extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this, scopeModel));
        // ③直接从当前对象成员属性extensionLoadersMap根据type获取对应的loader返回
        loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
        return loader;
    }

①直接通过new 一个ExtensionLoader对象(这里就会进行这个对象的一些初始化操作了,后续一些用到的属性都是在这个初始化操作完成的,我们后面遇到再重点提起)
②存入当前对象成员属性extensionLoadersMap
③直接从当前对象成员属性extensionLoadersMap根据type获取对应的loader返回

好,此时我们已经拿到ExtensionLoader对象了,可以调用getExtension来获取对应实例

    public T getExtension(String name) {
        // ①根据名字及允许包装来获取实例
        T extension = getExtension(name, true);
        // ②如果没有获取到,则抛异常
        if (extension == null) {
            throw new IllegalArgumentException("Not find extension: " + name);
        }
        return extension;
    }

①根据名字及允许包装来获取实例
②如果没有获取到,则抛异常

    public T getExtension(String name, boolean wrap) {
        checkDestroyed();
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        // ①如果name是"true"则获取默认的spi对象
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        // ②获取cacheKey,如果不允许包装,则通过拼接_origin来控制返回原对象
        String cacheKey = name;
        if (!wrap) {
            cacheKey += "_origin";
        }
        // ③获取生成的cacheKey对应的holder
        final Holder<Object> holder = getOrCreateHolder(cacheKey);
        // ④从holder中获取是否有对应对象
        Object instance = holder.get();
        // ⑤如果没有,对holder加锁双重检查后进行创建
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = createExtension(name, wrap);
                    // ⑥再将创建好的对象放进holder中
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

①如果name是"true"则获取默认的spi对象
②获取cacheKey,如果不允许包装,则通过拼接_origin来控制返回原对象
③获取生成的cacheKey对应的holder
④从holder中获取是否有对应对象
⑤如果没有,对holder加锁双重检查后进行创建
⑥再将创建好的对象放进holder中

    private T createExtension(String name, boolean wrap) {
        // ①获取ExtensionClassMap(也就是每个name对应的class全路径名),再从map中获取name对应的class全类名
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null || unacceptableExceptions.contains(name)) {
            throw findException(name);
        }
        try {
            // ②先根据当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据类型去获取对象
            T instance = (T) extensionInstances.get(clazz);

            if (instance == null) {
                //③如果没获取到,则根据class全类名创建实例,并放进当前loader对象属性成员extensionInstances(ConcurrentHashMap)中
                extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
                //④从当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据type对应的Class对象取出对应的实例
                instance = (T) extensionInstances.get(clazz);
                //⑤获取前置处理器,循环遍历调用
                instance = postProcessBeforeInitialization(instance, name);
                //⑥反射调用set方法将实例注入取出的实例属性
                injectExtension(instance);
                //⑦获取后置处理器,循环遍历调用
                instance = postProcessAfterInitialization(instance, name);
            }
            //⑧如果需要包装,将cachedWrapperClasses的包装Class集合放进wrapperClassesList并排序
            if (wrap) {
                List<Class<?>> wrapperClassesList = new ArrayList<>();
                if (cachedWrapperClasses != null) {
                    wrapperClassesList.addAll(cachedWrapperClasses);
                    wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                    Collections.reverse(wrapperClassesList);
                }

                if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                    //⑨循环遍历所有的包装Class,判断是否有Wrapper注解,如果有则根据注解上面的配置匹配过滤下当前包装Class
                    // 是否适用当前name对应的对象
                    for (Class<?> wrapperClass : wrapperClassesList) {
                        Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                        boolean match = (wrapper == null) ||
                            ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
                                !ArrayUtils.contains(wrapper.mismatches(), name));
                        if (match) {
                            //⑩如果匹配,拿到包装类 获取构造器 将被包装的类传入构造器反射 反射 创建实例,并注入其他属性返回
                            instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                            instance = postProcessAfterInitialization(instance, name);
                        }
                    }
                }
            }
            // 11.如果name对应的对象实现了Lifecycle接口,则调用器初始化方法,返回
            // Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
            initExtension(instance);
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
    }

①获取ExtensionClassMap(也就是每个name对应的class全路径名),再从map中获取name对应的class全类名
②先根据当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据类型去获取对象
③如果没获取到,则根据class全类名创建实例,并放进当前loader对象属性成员extensionInstances(ConcurrentHashMap)中
④从当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据type对应的Class对象取出对应的实例
⑤获取前置处理器,循环遍历调用
⑥反射调用set方法将实例注入取出的实例属性
⑦获取后置处理器,循环遍历调用
⑧如果需要包装,将cachedWrapperClasses的包装Class集合放进wrapperClassesList并排序
⑨循环遍历所有的包装Class,判断是否有Wrapper注解,如果有则根据注解上面的配置匹配过滤下当前包装Class是否适用当前name对应的对象
⑩如果匹配,拿到包装类 获取构造器 将被包装的类传入构造器反射 反射 创建实例,并注入其他属性返回
11.如果name对应的对象实现了Lifecycle接口,则调用器初始化方法,创建完成

接下来,我们深入一些重点方法来细化一些流程

首先看下第①步中如何获取ExtensionClassMap

    private Map<String, Class<?>> getExtensionClasses() {
        // ①先从当前loader对象的cachedClasses(Holder<Map<String, Class<?>>>)属性变量中获取
        Map<String, Class<?>> classes = cachedClasses.get();
        // ②如果没有,锁住holder对象双重检查锁之后进行加载
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    // ③再把加载到的Map<String, Class<?>>设置进holder即cachedClasses中
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

①先从当前loader对象的cachedClasses(Holder<Map<String, Class<?>>>)属性变量中获取
②如果没有,锁住holder对象双重检查锁之后进行加载
③再把加载到的Map<String, Class<?>>设置进holder即cachedClasses中

    private Map<String, Class<?>> loadExtensionClasses() {
        checkDestroyed();
        // ①设置当前loader对象默认的spi name,即给cachedDefaultName成员属性赋值
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();
        // ②循环遍历所有的加载策略,将各个类加载器加载路径下以接口命名的文件中
        // key(name),value(全类名)键值对加载进extensionClasses(Map<String, Class<?>>)中
        for (LoadingStrategy strategy : strategies) {
            loadDirectory(extensionClasses, strategy, type.getName());

            // compatible with old ExtensionFactory
            if (this.type == ExtensionInjector.class) {
                loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
            }
        }

        return extensionClasses;
    }

①设置当前loader对象默认的spi name,即给cachedDefaultName成员属性赋值
②循环遍历所有的加载策略,将各个类加载器加载路径下以接口命名的文件中key(name),value(全类名)键值对加载进extensionClasses(Map<String, Class<?>>)中

    private void loadDirectory(Map<String, Class<?>> extensionClasses, LoadingStrategy strategy, String type) {
        // ①根据加载策略类加载type对应文件下的key,value
        loadDirectoryInternal(extensionClasses, strategy, type);
        try {
            // ②兼容行为,把type全类名的org.apache改为com.alibaba再去加载一遍对应文件中的key,value
            String oldType = type.replace("org.apache", "com.alibaba");
            if (oldType.equals(type)) {
                return;
            }
            //if class not found,skip try to load resources
            ClassUtils.forName(oldType);
            loadDirectoryInternal(extensionClasses, strategy, oldType);
        } catch (ClassNotFoundException classNotFoundException) {

        }
    }

①根据加载策略类加载type对应文件下的key,value
②兼容行为,把type全类名的org.apache改为com.alibaba再去加载一遍对应文件中的key,value

    private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type) {
        // ①根据策略类拼接好文件名
        String fileName = loadingStrategy.directory() + type;
        try {
            List<ClassLoader> classLoadersToLoad = new LinkedList<>();

            // try to load from ExtensionLoader's ClassLoader first
            if (loadingStrategy.preferExtensionClassLoader()) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                    classLoadersToLoad.add(extensionLoaderClassLoader);
                }
            }

            if (specialSPILoadingStrategyMap.containsKey(type)){
                String internalDirectoryType = specialSPILoadingStrategyMap.get(type);
                //skip to load spi when name don't match
                if (!LoadingStrategy.ALL.equals(internalDirectoryType)
                    && !internalDirectoryType.equals(loadingStrategy.getName())){
                    return;
                }
                classLoadersToLoad.clear();
                classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());
            }else {
                // load from scope model
                Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();

                if (CollectionUtils.isEmpty(classLoaders)) {
                    Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);
                    if (resources != null) {
                        while (resources.hasMoreElements()) {
                            //② 根据文件名对应到类加载器上的文件路径加载文件中的内容,name作为key,value对应的Class作为value设置进extensionClasses
                            loadResource(extensionClasses, null, resources.nextElement(), loadingStrategy.overridden(),
                                loadingStrategy.includedPackages(),
                                loadingStrategy.excludedPackages(),
                                loadingStrategy.onlyExtensionClassLoaderPackages());
                        }
                    }
                } else {
                    classLoadersToLoad.addAll(classLoaders);
                }
            }

            Map<ClassLoader, Set<java.net.URL>> resources = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);
            resources.forEach(((classLoader, urls) -> {
                loadFromClass(extensionClasses, loadingStrategy.overridden(), urls, classLoader,
                    loadingStrategy.includedPackages(),
                    loadingStrategy.excludedPackages(),
                    loadingStrategy.onlyExtensionClassLoaderPackages());
            }));
        } catch (Throwable t) {
            logger.error("Exception occurred when loading extension class (interface: " +
                type + ", description file: " + fileName + ").", t);
        }
    }

①根据策略类拼接好文件名
② 根据文件名对应到类加载器上的文件路径加载文件中的内容,name作为key,value对应的Class作为value设置进extensionClasses

    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
                              java.net.URL resourceURL, boolean overridden, String[] includedPackages, String[] excludedPackages, String[] onlyExtensionClassLoaderPackages) {
        try {
            // ①获取url对应文件中的内容,将每行数据作为一个元素塞进list中
            List<String> newContentList = getResourceContent(resourceURL);
            String clazz;
            // ②遍历每行数据,将等号左边的值作为name,右边的值Class.forName获取clazz作为value放进extensionClasses
            for (String line : newContentList) {
                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) {
                            name = line.substring(0, i).trim();
                            clazz = line.substring(i + 1).trim();
                        } else {
                            clazz = line;
                        }
                        if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages) && isIncluded(clazz, includedPackages)
                            && !isExcludedByClassLoader(clazz, classLoader, onlyExtensionClassLoaderPackages)) {
                            loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
                        }
                    } 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);
        }
    }

①获取url对应文件中的内容,将每行数据作为一个元素塞进list中
②遍历每行数据,将等号左边的值作为name,右边的值Class.forName获取clazz作为value放进extensionClasses

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) {
        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注解,如果有就将clazz赋值给当前loader对象的cachedAdaptiveClass属性
        // ②如果是包装类,则将clazz塞进当前loader对象的cachedWrapperClasses(set)中
        // ③如果都不是,则进行加载进extensionClasses
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            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, overridden);
                }
            }
        }
    }

①判断是否有Adaptive注解,如果有就将clazz赋值给当前loader对象的cachedAdaptiveClass属性
②如果是包装类,则将clazz塞进当前loader对象的cachedWrapperClasses(set)中
③如果都不是,则进行加载extensionClasses

    private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {
        Class<?> c = extensionClasses.get(name);
        if (c == null || overridden) {
            extensionClasses.put(name, clazz);
        } else if (c != clazz) {
            // duplicate implementation is unacceptable
            unacceptableExceptions.add(name);
            String duplicateMsg = "Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
            logger.error(duplicateMsg);
            throw new IllegalStateException(duplicateMsg);
        }
    }

剥了这么多层洋葱,终于看到了put操作

此时我们就已经拿到了name对应的 clazz

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值