Dubbo spi (二)

前面讲了Java的spi机制,但是Java的spi并不能实现按需加载,它会加载接口的所有实现类,因此Dubbo并未使用Java的spi而是自己实现了一套SPI机制,将逻辑封装在ExtensionLoader中,实现按需加载

Dubbo spi示例

首先创建接口:

@SPI // 注意需要加上该注解
public interface SPIService {
    void sayHello();
}

创建接口实现类:

public class SPIServiceImplOne implements SPIService {

    @Override
    public void sayHello() {
        System.out.println("你好,我是实现类1");
    }
}

public class SPIServiceImplTwo implements SPIService {
    @Override
    public void sayHello() {
        System.out.println("你好,我是实现类2");
    }
}

在resource的META-INF下创建dubbo文件夹,并创建接口全限定名的文件:

META-INF/dubbo/com.lgx.dubbo.spi.SPIService

SPIServiceImplOne=com.lgx.dubbo.spi.impl.SPIServiceImplOne
SPIServiceImplTwo=com.lgx.dubbo.spi.impl.SPIServiceImplTwo

接下来进行测试:

@Test
public void testDubboSPI(){
    /**
     * 获取ExtensionLoader  (class到获取ExtensionLoader的映射保存到map中)
     */
    ExtensionLoader<SPIService> extensionLoader = ExtensionLoader.getExtensionLoader(SPIService.class);
    /**
     * 创建扩展点
     *      1. 通过getExtensionClasses 在指定目录下获取所有的扩展类(配置项名称”到“配置类”的映射保存在map中)
     *      2. 通过反射创建扩展对象  clazz.newInstance
     *      3. 向扩展对象中注入依赖  IOC
     *      4. 将扩展对象包裹在相应的Wrapper对象中   AOP
     */
    SPIService loaderOne = extensionLoader.getExtension("SPIServiceImplOne");
    loaderOne.sayHello();
    SPIService loaderTwo = extensionLoader.getExtension("SPIServiceImplTwo");
    loaderTwo.sayHello();
}

输出结果:
你好,我是实现类1
你好,我是实现类2

Dubbo spi的实现原理

首先看第一行:

ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(SPIService.class);

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!");
    }
    // 接口上是否标准了@SPI注解
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type (" + type +
                ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
    }
	// ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>()  从缓存中获取
    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;
}
private ExtensionLoader(Class<?> type) {
        this.type = type;
    // 这里涉及到自适应扩展 先忽略
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

接着分析这一行:

SPIService loaderOne = extensionLoader.getExtension("SPIServiceImplOne");

public T getExtension(String name) {
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    }
    // 获取默认的Extension
    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;
}

private T createExtension(String name) {
    	// 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            // 从缓存中获取
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
               // 获取不到创建实例,并加入缓存
               //map<class com.lgx.dubbo.spi.impl.SPIServiceImplTwo,SPIServiceImplTwo实例>
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // 依赖注入
            injectExtension(instance);
            // 对象包装
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                    type + ") couldn't be instantiated: " + t.getMessage(), t);
        }
}

createExtension分为四步:

  1. 加载配置文件,获取到配置项到配置类的映射关系<name,class>

  2. clazz.newInstance()创建实例,加入缓存

  3. 依赖注入

  4. 将创建的对象包装到Wrapper实例中

来看看第一步:

// 获取实现类的全限定名称加入到map中形成映射
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;
}

private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();
        Map<String, Class<?>> extensionClasses = new HashMap<>();
    	// DUBBO_INTERNAL_DIRECTORY = META-INF/dubbo/internal/
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    	// DUBBO_INTERNAL_DIRECTORY = META-INF/dubbo/
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    	// DUBBO_INTERNAL_DIRECTORY = META-INF/services/
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
        loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
        return extensionClasses;
}

我们是在META-INF/dubbo/这个目录下创建的 所以会从加载该目录下的文件

private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
    String fileName = dir + type;
    try {
        Enumeration<java.net.URL> urls;
        // 获取ClassLoader ==> AppClassLoader
        ClassLoader classLoader = findClassLoader();
        if (classLoader != null) {
            // 加载文件
            urls = classLoader.getResources(fileName);
        } else {
            urls = ClassLoader.getSystemResources(fileName);
        }
        if (urls != null) {
            while (urls.hasMoreElements()) {
                java.net.URL resourceURL = urls.nextElement();
                // 再这里将每一行的实现类名称和对应的Class类放入到map中形成映射
                loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } catch (Throwable t) {
        logger.error("Exception occurred when loading extension class (interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}
// 加载资源
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        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;
                            int i = line.indexOf('=');
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }
                            if (line.length() > 0) {
                                // 走到这里,加载类并加入缓存
                                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);
        }
}

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.");
        }
    	// 自适应扩展先不管
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        } else if (isWrapperClass(clazz)) { // 是否为包装类型 Wrapper
            cacheWrapperClass(clazz);
        } else {
            // 普通扩展类
            // 检测 clazz 是否有默认的构造方法,如果没有,则抛出异常
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                // 如果name为空,则从Extension注解中取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);
                }
            }
        }
}

第二步比较简单,来看看第三步:

private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            // 遍历该实例的所有方法
            for (Method method : instance.getClass().getMethods()) {
                // 是否为set方法
                if (isSetter(method)) {
                    // 是否需要自动注入 方法上是否有DisableInject注解
                    if (method.getAnnotation(DisableInject.class) != null) {
                        continue;
                    }
                    Class<?> pt = method.getParameterTypes()[0];
                    // 判断参数是否为原始类型
                    if (ReflectUtils.isPrimitives(pt)) {
                        continue;
                    }
                    try {
                        // 获取属性名 如: setPerson 则属性名为person
                        String property = getSetterProperty(method);
                        // 调用 SpiExtensionFactory的getExtension方法
                        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;
}
public class SpiExtensionFactory implements ExtensionFactory {

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // 是否为接口并且接口上标注了SPI注解
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
            if (!loader.getSupportedExtensions().isEmpty()) {
                // 获取自适应扩展
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

}

第四步暂时忽略

总结

dubbo的spi机制也比较简单,通过传入的实现类名去缓存找是否有对应的实例,没有就创建。创建的过程就是去META-INF/dubbo/、META-INF/dubbo/internal/、META-INF/services下查找配置文件进行加载,得到<配置名,配置类>的映射关系(其中包括自适应扩展,包装类和普通扩展类),加入到缓存中,根据传入的实现类的名称获取对应的Class类,最后进行实例化获取实现类实例(其中加入了IOC->setter依赖注入,AOP->Wrapper包装实例,并且有大量的缓存)

posted @ 2021-02-20 17:28  丁茜萌萌哒  阅读(39)  评论(0编辑  收藏  举报