• 1.读dubbo spi机制源码


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

    1. @Override
    2. @SuppressWarnings("unchecked")
    3. public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    4. checkDestroyed();
    5. if (type == null) {
    6. throw new IllegalArgumentException("Extension type == null");
    7. }
    8. if (!type.isInterface()) {
    9. throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
    10. }
    11. if (!withExtensionAnnotation(type)) {
    12. throw new IllegalArgumentException("Extension type (" + type +
    13. ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
    14. }
    15. // 1. find in local cache
    16. ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
    17. ExtensionScope scope = extensionScopeMap.get(type);
    18. if (scope == null) {
    19. SPI annotation = type.getAnnotation(SPI.class);
    20. scope = annotation.scope();
    21. extensionScopeMap.put(type, scope);
    22. }
    23. if (loader == null && scope == ExtensionScope.SELF) {
    24. // create an instance in self scope
    25. loader = createExtensionLoader0(type);
    26. }
    27. // 2. find in parent
    28. if (loader == null) {
    29. if (this.parent != null) {
    30. loader = this.parent.getExtensionLoader(type);
    31. }
    32. }
    33. // 3. create it
    34. if (loader == null) {
    35. loader = createExtensionLoader(type);
    36. }
    37. return loader;
    38. }

    ①首先去当前对象的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步骤

    1. private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
    2. ExtensionLoader<T> loader = null;
    3. if (isScopeMatched(type)) {
    4. // if scope is matched, just create it
    5. loader = createExtensionLoader0(type);
    6. }
    7. return loader;
    8. }

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

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

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

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

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

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

    1. public T getExtension(String name, boolean wrap) {
    2. checkDestroyed();
    3. if (StringUtils.isEmpty(name)) {
    4. throw new IllegalArgumentException("Extension name == null");
    5. }
    6. // ①如果name是"true"则获取默认的spi对象
    7. if ("true".equals(name)) {
    8. return getDefaultExtension();
    9. }
    10. // ②获取cacheKey,如果不允许包装,则通过拼接_origin来控制返回原对象
    11. String cacheKey = name;
    12. if (!wrap) {
    13. cacheKey += "_origin";
    14. }
    15. // ③获取生成的cacheKey对应的holder
    16. final Holder<Object> holder = getOrCreateHolder(cacheKey);
    17. // ④从holder中获取是否有对应对象
    18. Object instance = holder.get();
    19. // ⑤如果没有,对holder加锁双重检查后进行创建
    20. if (instance == null) {
    21. synchronized (holder) {
    22. instance = holder.get();
    23. if (instance == null) {
    24. instance = createExtension(name, wrap);
    25. // ⑥再将创建好的对象放进holder中
    26. holder.set(instance);
    27. }
    28. }
    29. }
    30. return (T) instance;
    31. }

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

    1. private T createExtension(String name, boolean wrap) {
    2. // ①获取ExtensionClassMap(也就是每个name对应的class全路径名),再从map中获取name对应的class全类名
    3. Class<?> clazz = getExtensionClasses().get(name);
    4. if (clazz == null || unacceptableExceptions.contains(name)) {
    5. throw findException(name);
    6. }
    7. try {
    8. // ②先根据当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据类型去获取对象
    9. T instance = (T) extensionInstances.get(clazz);
    10. if (instance == null) {
    11. //③如果没获取到,则根据class全类名创建实例,并放进当前loader对象属性成员extensionInstances(ConcurrentHashMap)中
    12. extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
    13. //④从当前loader对象属性成员extensionInstances(ConcurrentHashMap)中根据type对应的Class对象取出对应的实例
    14. instance = (T) extensionInstances.get(clazz);
    15. //⑤获取前置处理器,循环遍历调用
    16. instance = postProcessBeforeInitialization(instance, name);
    17. //⑥反射调用set方法将实例注入取出的实例属性
    18. injectExtension(instance);
    19. //⑦获取后置处理器,循环遍历调用
    20. instance = postProcessAfterInitialization(instance, name);
    21. }
    22. //⑧如果需要包装,将cachedWrapperClasses的包装Class集合放进wrapperClassesList并排序
    23. if (wrap) {
    24. List<Class<?>> wrapperClassesList = new ArrayList<>();
    25. if (cachedWrapperClasses != null) {
    26. wrapperClassesList.addAll(cachedWrapperClasses);
    27. wrapperClassesList.sort(WrapperComparator.COMPARATOR);
    28. Collections.reverse(wrapperClassesList);
    29. }
    30. if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
    31. //⑨循环遍历所有的包装Class,判断是否有Wrapper注解,如果有则根据注解上面的配置匹配过滤下当前包装Class
    32. // 是否适用当前name对应的对象
    33. for (Class<?> wrapperClass : wrapperClassesList) {
    34. Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
    35. boolean match = (wrapper == null) ||
    36. ((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
    37. !ArrayUtils.contains(wrapper.mismatches(), name));
    38. if (match) {
    39. //⑩如果匹配,拿到包装类 获取构造器 将被包装的类传入构造器反射 反射 创建实例,并注入其他属性返回
    40. instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
    41. instance = postProcessAfterInitialization(instance, name);
    42. }
    43. }
    44. }
    45. }
    46. // 11.如果name对应的对象实现了Lifecycle接口,则调用器初始化方法,返回
    47. // 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.
    48. initExtension(instance);
    49. return instance;
    50. } catch (Throwable t) {
    51. throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
    52. type + ") couldn't be instantiated: " + t.getMessage(), t);
    53. }
    54. }

    ①获取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

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

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

    1. private Map<String, Class<?>> loadExtensionClasses() {
    2. checkDestroyed();
    3. // ①设置当前loader对象默认的spi name,即给cachedDefaultName成员属性赋值
    4. cacheDefaultExtensionName();
    5. Map<String, Class<?>> extensionClasses = new HashMap<>();
    6. // ②循环遍历所有的加载策略,将各个类加载器加载路径下以接口命名的文件中
    7. // key(name),value(全类名)键值对加载进extensionClasses(Map<String, Class<?>>)中
    8. for (LoadingStrategy strategy : strategies) {
    9. loadDirectory(extensionClasses, strategy, type.getName());
    10. // compatible with old ExtensionFactory
    11. if (this.type == ExtensionInjector.class) {
    12. loadDirectory(extensionClasses, strategy, ExtensionFactory.class.getName());
    13. }
    14. }
    15. return extensionClasses;
    16. }

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

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

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

    1. private void loadDirectoryInternal(Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type) {
    2. // ①根据策略类拼接好文件名
    3. String fileName = loadingStrategy.directory() + type;
    4. try {
    5. List<ClassLoader> classLoadersToLoad = new LinkedList<>();
    6. // try to load from ExtensionLoader's ClassLoader first
    7. if (loadingStrategy.preferExtensionClassLoader()) {
    8. ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
    9. if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
    10. classLoadersToLoad.add(extensionLoaderClassLoader);
    11. }
    12. }
    13. if (specialSPILoadingStrategyMap.containsKey(type)){
    14. String internalDirectoryType = specialSPILoadingStrategyMap.get(type);
    15. //skip to load spi when name don't match
    16. if (!LoadingStrategy.ALL.equals(internalDirectoryType)
    17. && !internalDirectoryType.equals(loadingStrategy.getName())){
    18. return;
    19. }
    20. classLoadersToLoad.clear();
    21. classLoadersToLoad.add(ExtensionLoader.class.getClassLoader());
    22. }else {
    23. // load from scope model
    24. Set<ClassLoader> classLoaders = scopeModel.getClassLoaders();
    25. if (CollectionUtils.isEmpty(classLoaders)) {
    26. Enumeration<java.net.URL> resources = ClassLoader.getSystemResources(fileName);
    27. if (resources != null) {
    28. while (resources.hasMoreElements()) {
    29. //② 根据文件名对应到类加载器上的文件路径加载文件中的内容,name作为key,value对应的Class作为value设置进extensionClasses
    30. loadResource(extensionClasses, null, resources.nextElement(), loadingStrategy.overridden(),
    31. loadingStrategy.includedPackages(),
    32. loadingStrategy.excludedPackages(),
    33. loadingStrategy.onlyExtensionClassLoaderPackages());
    34. }
    35. }
    36. } else {
    37. classLoadersToLoad.addAll(classLoaders);
    38. }
    39. }
    40. Map<ClassLoader, Set<java.net.URL>> resources = ClassLoaderResourceLoader.loadResources(fileName, classLoadersToLoad);
    41. resources.forEach(((classLoader, urls) -> {
    42. loadFromClass(extensionClasses, loadingStrategy.overridden(), urls, classLoader,
    43. loadingStrategy.includedPackages(),
    44. loadingStrategy.excludedPackages(),
    45. loadingStrategy.onlyExtensionClassLoaderPackages());
    46. }));
    47. } catch (Throwable t) {
    48. logger.error("Exception occurred when loading extension class (interface: " +
    49. type + ", description file: " + fileName + ").", t);
    50. }
    51. }

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

    1. private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
    2. java.net.URL resourceURL, boolean overridden, String[] includedPackages, String[] excludedPackages, String[] onlyExtensionClassLoaderPackages) {
    3. try {
    4. // ①获取url对应文件中的内容,将每行数据作为一个元素塞进list中
    5. List<String> newContentList = getResourceContent(resourceURL);
    6. String clazz;
    7. // ②遍历每行数据,将等号左边的值作为name,右边的值Class.forName获取clazz作为value放进extensionClasses
    8. for (String line : newContentList) {
    9. final int ci = line.indexOf('#');
    10. if (ci >= 0) {
    11. line = line.substring(0, ci);
    12. }
    13. line = line.trim();
    14. if (line.length() > 0) {
    15. try {
    16. String name = null;
    17. int i = line.indexOf('=');
    18. if (i > 0) {
    19. name = line.substring(0, i).trim();
    20. clazz = line.substring(i + 1).trim();
    21. } else {
    22. clazz = line;
    23. }
    24. if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages) && isIncluded(clazz, includedPackages)
    25. && !isExcludedByClassLoader(clazz, classLoader, onlyExtensionClassLoaderPackages)) {
    26. loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
    27. }
    28. } catch (Throwable t) {
    29. IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type +
    30. ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
    31. exceptions.put(line, e);
    32. }
    33. }
    34. }
    35. } catch (Throwable t) {
    36. logger.error("Exception occurred when loading extension class (interface: " +
    37. type + ", class file: " + resourceURL + ") in " + resourceURL, t);
    38. }
    39. }

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

    1. private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
    2. boolean overridden) {
    3. if (!type.isAssignableFrom(clazz)) {
    4. throw new IllegalStateException("Error occurred when loading extension class (interface: " +
    5. type + ", class line: " + clazz.getName() + "), class "
    6. + clazz.getName() + " is not subtype of interface.");
    7. }
    8. // ①判断是否有Adaptive注解,如果有就将clazz赋值给当前loader对象的cachedAdaptiveClass属性
    9. // ②如果是包装类,则将clazz塞进当前loader对象的cachedWrapperClasses(set)中
    10. // ③如果都不是,则进行加载进extensionClasses
    11. if (clazz.isAnnotationPresent(Adaptive.class)) {
    12. cacheAdaptiveClass(clazz, overridden);
    13. } else if (isWrapperClass(clazz)) {
    14. cacheWrapperClass(clazz);
    15. } else {
    16. if (StringUtils.isEmpty(name)) {
    17. name = findAnnotationName(clazz);
    18. if (name.length() == 0) {
    19. throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
    20. }
    21. }
    22. String[] names = NAME_SEPARATOR.split(name);
    23. if (ArrayUtils.isNotEmpty(names)) {
    24. cacheActivateClass(clazz, names[0]);
    25. for (String n : names) {
    26. cacheName(clazz, n);
    27. saveInExtensionClass(extensionClasses, clazz, n, overridden);
    28. }
    29. }
    30. }
    31. }

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

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

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

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

  • 相关阅读:
    springboot+jsp体育器材租赁java场地预约系统ssm
    【Python】图像和办公文档的处理
    什么是React的虚拟DOM(Virtual DOM)?它的作用是什么?
    文件上传渗透实验
    Elastic stack8.10.4搭建、启用安全认证,启用https,TLS,SSL 安全配置详解
    面试题-多线程-解释什么是死锁( deadlock )
    Maven配置
    计及需求响应的粒子群算法求解风能、光伏、柴油机、储能容量优化配置(Matlab代码实现)
    c++与c 的知识点
    JS逆向实战21——某查查webpack密码加密
  • 原文地址:https://blog.csdn.net/Niel_3/article/details/125480684