半日闲

因过竹院逢僧话,又得浮生半日闲

0%

Dubbo源码解读4-扩展点类ExtensionLoader SPI加载所有实现类信息

逻辑解析

  1. 根据类加载策略来进行SPI扩展点配置文件的存放位置查找。
  2. 将类全路径报名作为文件名称对配置文件进行检索,得到若干个文件路径。
  3. 解析配置文件中的name和实现类全路径键值对,从虚拟机中加载该类。
  4. 加载类过程中,如果该实现类是否被@Adaptive修饰,则表示该实现类是SPI接口的静态适配类,用作getAdaptiveExtension返回。如果该实现类是包装类(通过判断构造方法是否有自身SPI接口注入), 如果存在,则添加到cachedWrapperClasses变量中。第三种情况则在分为两步操作,先判定改实现类是否被@Activate注解修饰,如果是,则将信息保存到cachedActivates变量中,如果不是,则在查找是否被alibaba包下面的@Activate注解修饰,如果是,则在保存到cachedActivates中,如果不是,跳过。第二步在进行名称缓存,并进行实现类信息保存到Map<String, Class<?>>并返回,最终保存到cachedClasses变量中。

    相关代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    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());
    loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"),
    strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
    }
    return extensionClasses;
    }
    private void cacheDefaultExtensionName() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if (defaultAnnotation == null) {
    return;
    }
    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];
    }
    }
    }
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
    boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
    String fileName = dir + type;
    try {
    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);
    }
    }
    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;
    String clazz = null;
    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();
    clazz = line.substring(i + 1).trim();
    } else {
    clazz = line;
    }
    if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
    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);
    }
    }
    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)) {
    cacheAdaptiveClass(clazz, overridden);
    } 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, overridden);
    }
    }
    }
    }