Dubbo拓展点加载机制源码分析

Dubbo拓展类的特性

(1)自动包装:ExtensionLoader在加载拓展时,如果发现这个拓展类包含其他拓展点作为构造函数的参数,这个拓展类就会被认为是Wrapper类。

这是一种装饰器模式,把通用的抽象逻辑进行封装或对子类进行增强,让子类可以更加专注具体的实现。

(2)自动加载:如果某个拓展类是另一个拓展点类的成员属性,并且拥有setter方法,那么框架也会自动注入对应的拓展点实例。

(3)自适应:使用@Adaptive注解可以动态通过URL中的参数来确定要使用哪个具体的实现类,从而解决自动加载中的实例注入问题。

(4)自动激活:使用@Activate注解,可以标记对应的拓展点默认被激活启用。该注解可以通过传入不同的参数,设置拓展点在不同的条件下被自动激活。主要使用场景是某个拓展点的多个实现类需要同时启用。

ExtensionFactory

ExtensionFactory有三个子类实现,包括:AdaptiveExtensionFactory、SpiExtensionFactory和SpringExtensionFactory。其中AdaptiveExtensionFactory优先级最高,因为AdaptiveExtensionFactory类上面带有@Adaptive注解。

AdaptiveExtensionFactory 的构造方法会先构造一个ExtensionFactory的拓展加载器,然后从资源文件获取SpiExtensionFactory和SpringExtensionFactory放入factories中。AdaptiveExtensionFactory#getExtension就是调用SpiExtensionFactory#getExtension和SpringExtensionFactory#getExtension获取拓展类。SpringExtensionFactory先根据名称从IOC容器中获取拓展类,获取不到,再根据类型从IOC容器获取。SpiExtensionFactory针对带有@SPI注解的接口,返回Adapative拓展实现类(如果不存在带有@Adaptive的实现类,就由Dubbo通过javassist自动生成)。

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    
    

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
    
    
        ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        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;
    }

}

ExtensionLoader

ExtensionLoader#getExtensionLoader先从集合中获取指定Class类型的拓展加载器,如果获取不到就创建一个,并放入集合中。

//拓展加载器集合
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    
    
    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的构造方法会去判断传入的Class类型是否是ExtensionFactory,如果不是就会获取ExtensionFactory的Adaptive自适应拓展类。

//对象工厂
private final ExtensionFactory objectFactory;

//实例化一个ExtensionLoader的时候会去创建一个对象工厂
private ExtensionLoader(Class<?> type) {
    
    
    this.type = type;
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

ExtensionLoader#getAdaptiveExtension用于获取自适应的拓展类。会先从一个Holder对象中获取实例,如果获取不到,对Holder对象进行同步,再次判断实例是否为空,如果为空,调用ExtensionLoader#createAdaptiveExtension进行创建。

private final Holder<Object> cachedAdaptiveInstance = new Holder<>();

public T getAdaptiveExtension() {
    
    
    Object instance = cachedAdaptiveInstance.get();
    if (instance == null) {
    
    
        if (createAdaptiveInstanceError == null) {
    
    
            synchronized (cachedAdaptiveInstance) {
    
    
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
    
    
                    try {
    
    
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
    
    
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        } else {
    
    
            throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }

    return (T) instance;
}

通过Class.newInstance方法实例化一个对象,并通过ExtensionLoader#injectExtension替实例对象的属性赋值(依赖注入)。

private T createAdaptiveExtension() {
    
    
    try {
    
    
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
    
    
        throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
}

先调用ExtensionLoader#getExtensionClasses获取一个带有@Adaptive注解的拓展类。如果获取不到,再调用ExtensionLoader#createAdaptiveExtensionClass生成一个。

private Class<?> getAdaptiveExtensionClass() {
    
    
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
    
    
        return cachedAdaptiveClass;
    }
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

获取cacheClasses对象,获取不到,调用ExtensionLoader#loadExtensionClasses获取。

private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();

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

在给定的资源文件夹目录下查找指定名称的类的拓展类。

private static final String SERVICES_DIRECTORY = "META-INF/services/";
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";

private Map<String, Class<?>> loadExtensionClasses() {
    
    
    cacheDefaultExtensionName();

    Map<String, Class<?>> extensionClasses = new HashMap<>();
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
    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;
}

如果给定的type类型带有@SPI注解,将属性value值缓存为默认的拓展名。如果value值经过逗号分隔之后有多个,抛出More than 1 default extension name on extension异常。

private void cacheDefaultExtensionName() {
    
    
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if (defaultAnnotation != null) {
    
    
        String value = defaultAnnotation.value();
        if ((value = value.trim()).length() > 0) {
    
    
            String[] names = NAME_SEPARATOR.split(value);
            if (names.length > 1) {
    
    
                throw new IllegalStateException("More than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if (names.length == 1) {
    
    
                cachedDefaultName = names[0];
            }
        }
    }
}

根据给定的文件夹路径,获取文件夹下面指定Class类型的资源信息。遍历每一个文件,读取文件中的每一个KeyValue信息。

private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
    
    
    String fileName = dir + type;
    try {
    
    
        Enumeration<java.net.URL> urls;
        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();
                loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } catch (Throwable t) {
    
    
        logger.error("Exception occurred when loading extension class (interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}

读取资源文件每一行内容。每一行查找#字符(注释字符)的位置,截取位置0到#字符前一个位置,再获取拓展类别名(等号前面的值)和全限定类名(等号后面的值),利用Class.forName(String name, boolean initialize, ClassLoader loader)获得字符串参数中指定的类,并初始化该类。

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);
    }
}

判断clazz是否是给定type(实例化ExtensionLoader传入的类型)的子类,如果不是抛出异常。
判断clazz是否带有@Adaptive注解,如果有,调用ExtensionLoader#cacheAdaptiveClass方法缓存这个类到cachedAdaptiveClass集合。
判断clazz是否是包装wrapper类,如果是,添加到包装类集合。
判断资源文件的拓展名为空,根据clazz名称和type名称获取拓展名,如果拓展名依然为空,抛出No such extension name for the class异常。
拓展名根据逗号分割,第一个拓展名缓存到cachedActivates集合。遍历每一个拓展名,缓存到cachedNames集合和extensionClasses集合。

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)) {
    
    
        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);
            }
        }
    }
}

缓存Adaptive拓展类。如果超过1个子类带有@Adaptive注解就会抛出More than 1 adaptive class found异常。

private void cacheAdaptiveClass(Class<?> clazz) {
    
    
    if (cachedAdaptiveClass == null) {
    
    
        cachedAdaptiveClass = clazz;
    } else if (!cachedAdaptiveClass.equals(clazz)) {
    
    
        throw new IllegalStateException("More than 1 adaptive class found: "
                + cachedAdaptiveClass.getClass().getName()
                + ", " + clazz.getClass().getName());
    }
}

判断是否是包装类。clazz是否具有只有给定type类型一个入参的构造方法,如果有,说明是包装wrapper类;如果没有,说明不是包装wrapper类。

private boolean isWrapperClass(Class<?> clazz) {
    
    
    try {
    
    
        clazz.getConstructor(type);
        return true;
    } catch (NoSuchMethodException e) {
    
    
        return false;
    }
}

缓存包装类。实例化一个HashSet集合用于存储包装类。

private void cacheWrapperClass(Class<?> clazz) {
    
    
    if (cachedWrapperClasses == null) {
    
    
        cachedWrapperClasses = new ConcurrentHashSet<>();
    }
    cachedWrapperClasses.add(clazz);
}

判断给定clazz类型是否带有@Extension注解,如果有,直接返回@Extension注解的value属性值。如果没有,获取给定clazz的名称,如果是以type名字结尾的,就截取除去type名称的部分(如:SpiExtensionFactory-ExtensionFactory=Spi),转成小写后返回。

private String findAnnotationName(Class<?> clazz) {
    
    
    org.apache.dubbo.common.Extension extension = clazz.getAnnotation(org.apache.dubbo.common.Extension.class);
    if (extension == null) {
    
    
        String name = clazz.getSimpleName();
        if (name.endsWith(type.getSimpleName())) {
    
    
            name = name.substring(0, name.length() - type.getSimpleName().length());
        }
        return name.toLowerCase();
    }
    return extension.value();
}

判断给定的clazz是否带有@Activate注解,如果有,缓存到cachedActivates集合。如果没有,判断是否带有ailibaba的@Activate注解,如果有,缓存到cachedActivates集合。

private void cacheActivateClass(Class<?> clazz, String name) {
    
    
    Activate activate = clazz.getAnnotation(Activate.class);
    if (activate != null) {
    
    
        cachedActivates.put(name, activate);
    } else {
    
    
        // support com.alibaba.dubbo.common.extension.Activate
        com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
        if (oldActivate != null) {
    
    
            cachedActivates.put(name, oldActivate);
        }
    }
}

判断cacheNames集合中是否存在指定的clazz的key,如果不存在,添加到集合。

private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<>();

private void cacheName(Class<?> clazz, String name) {
    
    
    if (!cachedNames.containsKey(clazz)) {
    
    
        cachedNames.put(clazz, name);
    }
}

将指定的clazz放入extensionClasses集合。

private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
    
    
    Class<?> c = extensionClasses.get(name);
    if (c == null) {
    
    
        extensionClasses.put(name, clazz);
    } else if (c != clazz) {
    
    
        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName());
    }
}

获取实例类全部的方法,判断是否是符合条件的set方法,如果是,通过ExtensionFactory获取一个拓展类。

private T injectExtension(T instance) {
    
    
    try {
    
    
        if (objectFactory != null) {
    
    
            for (Method method : instance.getClass().getMethods()) {
    
    
                if (isSetter(method)) {
    
    
                    /**
                     * 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 {
    
    
                        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;
}

假设方法的名称是setName,会返回name。去掉set,将set后面的首字母转成小写返回。

private String getSetterProperty(Method method) {
    
    
    return method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
}

判断一个方法是否以set开头,是否只有一个入参,是否是publie方法,如果都是,返回true。

private boolean isSetter(Method method) {
    
    
    return method.getName().startsWith("set")
            && method.getParameterTypes().length == 1
            && Modifier.isPublic(method.getModifiers());
}

如果没有找到一个带有@Adaptive注解的拓展类,就生成一个。默认用JavassistCompiler进行生成。Compiler带有@Adaptive的实现类是AdaptiveCompiler,AdaptiveCompiler#complie方法是调用SPI(“javassist”)实现的。

private Class<?> createAdaptiveExtensionClass() {
    
    
    String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
    ClassLoader classLoader = findClassLoader();
    org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

添加了SPI注解,默认实现是JavassistCompiler。

@SPI("javassist")
public interface Compiler {
    
    
    Class<?> compile(String code, ClassLoader classLoader);
}

AdaptiveCompiler#compile先获取Compiler的拓展加载器,如果没有指定调用哪一个拓展类,就调用SPI注解默认值的拓展类JavassistCompiler。
通过javassist自动生成和编译一个Adaptive类。

@Adaptive
public class AdaptiveCompiler implements Compiler {
    
    

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
    
    
        DEFAULT_COMPILER = compiler;
    }

    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
    
    
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
    
    
            compiler = loader.getExtension(name);
        } else {
    
    
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

}

ExtensionLoader#getExtension根据指定的名称获取拓展类。如果传入的拓展类名称是true,会返回默认拓展类。如果cachedInstances中无法获取到指定名称的实例,调用ExtensionLoader#createExtension创建实例。

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

从class缓存中获取指定名称的class,从EXTENSION_INSTANCES中根据指定的类获取实例,如果获取不到,实例化一个。调用ExtensionLoader#injectExtension替实例的所有set方法依赖注入。如果有包装类,用包装类装饰原来的实例。

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) {
    
    
            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);
    }
}

参考

[Dubbo拓展点加载机制] (https://blog.csdn.net/u012734723/article/details/107467689)
《深入理解Apache Dubbo与实战》

猜你喜欢

转载自blog.csdn.net/u012734723/article/details/120929543
今日推荐