Dubbo 源码解析(1) - Dubbo SPI
1. Dubbo SPI 简介、小Demo
Dubbo SPI 和 Demo 直接看官网 https://dubbo.apache.org/zh/docs/v2.7/dev/source/dubbo-spi/
2. Dubbo SPI 源码分析
直接进入 ExtensionLoader#getExtensionLoader 方法
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; }
ExtensionLoader#getExtensionLoader 方法很简单,先从 EXTENSION_LOADERS 缓存中获取一个 ExtensionLoader, 如果缓存中没有, new 一个 ExtensionLoader 加入缓存并返回。结束
进入 ExtensionLoader#getExtension(java.lang.String) 方法
public T getExtension(String name) { return getExtension(name, true); }
一个空壳方法,调用同名构造方法 ExtensionLoader#getExtension(java.lang.String, boolean)
进入 ExtensionLoader#getExtension(java.lang.String, boolean) 方法
/** * 真正找到给定 name 的 extension 的方法, * 先从 {@link ExtensionLoader#cachedInstances} 缓存中获取 extension, * 如果缓存中不存在, 调用 {@link ExtensionLoader#createExtension(java.lang.String, boolean)} * 创建一个 extension 加入到缓存中并返回 * @param name * @param wrap * @return */ public T getExtension(String name, boolean wrap) { 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, wrap); holder.set(instance); } } } return (T) instance; }
这才是真正获取 extension 的方法,先调用 ExtensionLoader#getOrCreateHolder 方法从 cachedInstances 缓存中获取被 Holder 包装的 extension 实例
private Holder<Object> getOrCreateHolder(String name) { Holder<Object> holder = cachedInstances.get(name); if (holder == null) { cachedInstances.putIfAbsent(name, new Holder<>()); holder = cachedInstances.get(name); } return holder; }
如果实例不存在,使用 DCL 方式加锁,调用 ExtensionLoader#createExtension 方法创建一个 extension 实例,加入holder,最后返回实例
进入 ExtensionLoader#createExtension 方法和
/** * 创建 extension instance, * STEP1 从 {@link ExtensionLoader#cachedClasses} 缓存中取出 extension class, * 如果 cachedClasses 不存在, 调用 {@link ExtensionLoader#loadExtensionClasses()}加载所有 extension class 加入缓存并返回 * STEP2 从 {@link ExtensionLoader#EXTENSION_INSTANCES} 缓存中取出 extension class 的 instance, * 如果 instance 为空, 通过反射创建一个 instance 加入 EXTENSION_INSTANCES 缓存中 * STEP3 调用 {@link ExtensionLoader#injectExtension(java.lang.Object)} 注入值,这一步是 Dubbo IOC 的具体实现 * STEP4 迭代 {@link ExtensionLoader#cachedWrapperClasses} 创建 wrapper, 这一步是 Dubbo AOP 的具体实现 * STEP5 调用 {@link ExtensionLoader#initExtension(java.lang.Object)} 初始化 instance * 返回 instance * @param name * @param wrap * @return */ @SuppressWarnings("unchecked") private T createExtension(String name, boolean wrap) { /* 先从 cachedClasses 缓存中取出 extension class, * 如果 cachedClasses 不存在, 调用 loadExtensionClasses() 加载 extension class 加入缓存并返回 */ Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { //从 EXTENSION_INSTANCES 缓存中取出 extension class 的 instance, // 如果 instance 为空, 通过反射创建一个instance 加入 EXTENSION_INSTANCES 缓存中 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } //为 extension 注入值,其实就是调用 extension 的 setter 方法设置值 injectExtension(instance); if (wrap) { List<Class<?>> wrapperClassesList = new ArrayList<>(); if (cachedWrapperClasses != null) { wrapperClassesList.addAll(cachedWrapperClasses); wrapperClassesList.sort(WrapperComparator.COMPARATOR); Collections.reverse(wrapperClassesList); } if (CollectionUtils.isNotEmpty(wrapperClassesList)) { for (Class<?> wrapperClass : wrapperClassesList) { Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class); if (wrapper == null || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } } } initExtension(instance); return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: " + t.getMessage(), t); } }
ExtensionLoader#createExtension 方法会调用 ExtensionLoader#getExtensionClasses 方法,
进入 ExtensionLoader#getExtensionClasses 方法和 createExtension 方法一起看
/** * 先加载所有扩展类保存到缓存中再返回 */ 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; }
ExtensionLoader#createExtension 主要走以下几步:
- STEP1:从 cachedClasses 中缓存中获取所有 extension class,如果缓存中取到的为空,使用 DCL 方式加锁,调用 ExtensionLoader#loadExtensionClasses 方法加载所有 extension class 加入缓存并返回;
- STEP2: 从 extension class 列表中选择一个与 name 对应的 class,如果 class 为空,直接抛出异常,如果 class 不为空,从 EXTENSION_INSTANCES 缓存中根据 class 获取一个 instance,如果 instance 为空,通过反射创建一个 instance 并加入缓存;
- STEP3:调用 ExtensionLoader#injectExtension 方法注入值,这一步其实就是调用 instance 的 setter 设置值,这一步其实就是 Dubbo IOC 的具体实现
- STEP4:迭代 cachedWrapperClasses 属性创建 wrapper,这一步其实就是 Dubbo AOP 的具体实现
- STEP5:调用 ExtensionLoader#initExtension 方法初始化 instance, 最后返回
进入 ExtensionLoader#loadExtensionClasses 方法
/** * 加载指定 {@link ExtensionLoader#type} 类型的 Class 列表, * 迭代 {@link ExtensionLoader#strategies} 并通过调用{@link ExtensionLoader#loadDirectory(java.util.Map, java.lang.String, java.lang.String, boolean, boolean, java.lang.String...)} * 加载 extension class * strategies 主要有三个实现类 * 1. {@link DubboInternalLoadingStrategy}, 负责加载 META-INF/dubbo/internal/ 目录下的 class * 2. {@link DubboLoadingStrategy}, 负责加载 META-INF/dubbo/ 目录下的 class * 2. {@link ServicesLoadingStrategy}, 负责加载 META-INF/services/ 目录下的 class * synchronized in getExtensionClasses */ private Map<String, Class<?>> loadExtensionClasses() { cacheDefaultExtensionName(); Map<String, Class<?>> extensionClasses = new HashMap<>(); for (LoadingStrategy strategy : strategies) { loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); //这一步是为了兼容老版本的dubbo设置的,dubbo 未交给 apache 管理之前包名是以 com.alibaba 开头 loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); } return extensionClasses; }
这一步其实就是迭代 ExtensionLoader#strategies 属性并通过调用 ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) 方法来加载 extension class,strategies 主要有三个实现,分别是
- DubboInternalLoadingStrategy, 负责加载 META-INF/dubbo/internal/ 目录下的 class
- DubboLoadingStrategy, 负责加载 META-INF/dubbo/ 目录下的 class
- ServicesLoadingStrategy, 负责加载 META-INF/services/ 目录下的 class
进入ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) 方法
/** * 加载指定 dir 目录下的 class 并保存到 extensionClasses 中, * 下一步调用调用 {@link ExtensionLoader#loadResource(java.util.Map, java.lang.ClassLoader, java.net.URL, boolean, java.lang.String...)} 加载指定资源 * @param extensionClasses 加载的 class 的保存集合 * @param dir 加载的目录 * @param type 加载的类型 * @param extensionLoaderClassLoaderFirst 是否先从ExtensionLoader的类加载器加载, 一般情况下为 false * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true * @param excludedPackages 要排除的加载的包 */ private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) { String fileName = dir + type; try { //获取指定 dir 下的 type 名称命名的文件 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); } } 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(); //加载资源 loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages); } } } catch (Throwable t) { logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", t); } }
这一步先分别尝试通过当前线程的类加载器和加载 ExtensionLoader 的类加载器来加载资源,如果都加载失败,下一步再通过 ExtensionLoader#loadResource 方法加载资源
进入 ExtensionLoader#loadResource 方法
/** * 加载指定 resourceURL 下的资源文件, * 下一步调用 {@link ExtensionLoader#loadClass(java.util.Map, java.net.URL, java.lang.Class, java.lang.String, boolean)} 加载资源文件中的指定类 * @param extensionClasses 加载的 class 的保存集合 * @param classLoader 类加载器 * @param resourceURL 要加载的资源文件的 URL * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true * @param excludedPackages 要排除的加载的包 */ private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL, boolean overridden, String... excludedPackages) { try { 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; //以等号为分隔符将 line 分隔成两部分 int i = line.indexOf('='); if (i > 0) { name = line.substring(0, i).trim(); line = line.substring(i + 1).trim(); } if (line.length() > 0 && !isExcluded(line, excludedPackages)) { //加载指定类 loadClass(extensionClasses, resourceURL, Class.forName(line, 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); } }
这一步再调用 ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法加载资源文件中的指定类
进入 ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法
/** * 加载指定类 * @param extensionClasses 加载的 class 的保存集合 * @param resourceURL 资源文件URL * @param clazz 要加载的类 * @param name extensionClasses 中要保存的类的key * @param overridden 是否要将后加载的 class 覆盖前加载的同名的 class,一般情况下为 true * @throws NoSuchMethodException */ private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name, boolean overridden) 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."); } if (clazz.isAnnotationPresent(Adaptive.class)) { //如果 class 加上了 Adaptive 注解,class 赋值给 cachedAdaptiveClass 属性当做缓存保存起来 cacheAdaptiveClass(clazz, overridden); } else if (isWrapperClass(clazz)) { //如果是包装类,class 加入 cachedWrapperClasses 缓存 cacheWrapperClass(clazz); } else { // 程序进入此分支,表明 clazz 是一个普通的拓展类 clazz.getConstructor(); // 如果 name 为空,则尝试从 Extension 注解中获取 name,或使用小写的类名作为 name 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); } } //将 name 用逗号分隔,一个 name 可以变成多个 name String[] names = NAME_SEPARATOR.split(name); if (ArrayUtils.isNotEmpty(names)) { //如果需要缓存到 cachedActivates 中,将第一个 name 作为 cachedActivates 集合中的key cacheActivateClass(clazz, names[0]); for (String n : names) { //保存根据 class 查 name 的 Map 集合 cacheName(clazz, n); //加载的 class 保存到 extensionClasses 中 saveInExtensionClass(extensionClasses, clazz, n, overridden); } } } }
ExtensionLoader#loadClass(Map, URL, Class, String, boolean) 方法才是最终加载 extension class 的方法,该方法会先判断类上有没有加 @Adaptive 注解,如果加了,保存到 cachedAdaptiveClass 缓存中,再判断是不是一个 wrapper class,如果是,加入 cachedWrapperClasses 缓存中,如果这两个判断都不是,表明当前的 class 是一个普通的 class,先判断如果指定 name 为空, name 重新赋值为 @Extension 注解中的 value 或者是直接是类名简写。将 name 以 “,” 分隔并迭代, 如果需要缓存到 cachedActivates 中,将第一个 name 作为 cachedActivates 集合中的key,保存到 class -> name 的缓存 cachedNames 中。至此 extension class 全部加载完毕
loadExtensionClasses 总结:ExtensionLoader#loadExtensionClasses -> ExtensionLoader#loadDirectory(Map, String, String, boolean, boolean, String...) -> ExtensionLoader#loadResource -> ExtensionLoader#loadClass(Map, URL, Class, String, boolean)
进入 ExtensionLoader#injectExtension 方法
/** * 为 instance 实例注入值, * 具体执行步骤查找所有 setter 方法,并调用 {@link ExtensionLoader#objectFactory} 获取要注入的值通过反射注入 * objectFactory 通常是 {@link AdaptiveExtensionFactory}, * AdaptiveExtensionFactory 保存了一个 {@link AdaptiveExtensionFactory#factories} 集合 * factories 保存了 {@link SpiExtensionFactory} 和 {@link org.apache.dubbo.config.spring.extension.SpringExtensionFactory} * 两个对象获取具体需要注入的值 * @param instance * @return */ private T injectExtension(T instance) { if (objectFactory == null) { return instance; } try { for (Method method : instance.getClass().getMethods()) { //判断是不是 setter 方法 if (!isSetter(method)) { continue; } //检查方法上有没有 DisableInject 注解 /** * Check {@link DisableInject} to see if we need auto injection for this property */ if (method.getAnnotation(DisableInject.class) != null) { continue; } Class<?> pt = method.getParameterTypes()[0]; if (ReflectUtils.isPrimitives(pt)) { continue; } try { //获取属性名称并从 objectFactory 根据属性类型和名称获取值并通过反射赋值 String property = getSetterProperty(method); Object object = objectFactory.getExtension(pt, property); if (object != null) { method.invoke(instance, object); } } catch (Exception e) { logger.error("Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
ExtensionLoader#injectExtension 方法的作用就是为 instance 实例注入值,具体执行步骤查找所有 setter 方法,并调用 ExtensionLoader#objectFactory 获取要注入的值通过反射注入,objectFactory 通常是 AdaptiveExtensionFactory,AdaptiveExtensionFactory 保存了一个 AdaptiveExtensionFactory#factories 集合,factories 保存了 SpiExtensionFactory 和 SpringExtensionFactory 两个对象获取具体需要注入的值
进入 ExtensionLoader#initExtension 方法
private void initExtension(T instance) { if (instance instanceof Lifecycle) { Lifecycle lifecycle = (Lifecycle) instance; lifecycle.initialize(); } }
ExtensionLoader#initExtension 方法就是判断 instance是否实现自 Lifecycle, 如果是,调用其 initialize 方法
至此 Dubbo SPI 加载 extension 结束

浙公网安备 33010602011771号