『Dubbo SPI源码分析』Wrapper 机制分析

Dubbo Wrapper 机制分析

  1. 创建测试 demo
  • 首先创建一个接口,举例为 Car
package com.luban.dubbo_spi.api;

@SPI
public interface Car {
    public void getColor();
}
  • 根据接口,先创建一个实现类
package com.luban.dubbo_spi.impl;

public class RedCar implements Car {

    public void getColor() {
        System.out.println("red");
    }
}
  • 创建实现类的包装类
package com.luban.dubbo_spi.impl;

public class CarWrapper implements Car{

    private Car car;

    public CarWrapper(Car car) {
        System.out.println("12");
        this.car = car;
    }

    @Override
    public void getColor() {
        car.getColor();
    }

    @Override
    public void getColorForUrl(URL url) {
    }
}
  • 然后在 resources 创建一个目录 META-INF.services 目录
  • 并在 META-INF.services 目录中创建文件 com.luban.dubbo_spi.api.Car 一定要与接口同名
red = com.luban.dubbo_spi.impl.RedCar
com.luban.dubbo_spi.impl.CarWrapper
  • 创建主程序测试 @SPI
public class CarDemo {

    public static void main(String[] args) {
        ExtensionLoader<Car> extensionLoader =
                ExtensionLoader.getExtensionLoader(Car.class);

        Car redCar = extensionLoader.getExtension("red");
        redCar.getColor();
    }
}
  1. 首先通过 ExtensionLoader.getExtensionLoader() 获取加载器
public class CarDemo {

    public static void main(String[] args) {
        // 1. 获取加载器
        ExtensionLoader<Car> extensionLoader =
                ExtensionLoader.getExtensionLoader(Car.class);
       ...
    }
}
  1. 在执行 getExtensionLoader() 时,会先判断传入的 Car.class 有没有标注 @SPI。然后通过 EXTENSION_LOADERS 属性获取是否有创建好的 ExtensionLoader,没有就执行创建
public class ExtensionLoader<T> {

    // 缓存 ExtensionLoader,每个接口对应一个 ExtensionLoader
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
    ...
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {// type = interface com.luban.dubbo_spi.api.Car
            throw new IllegalArgumentException("Extension type == null");
        }
        if (!type.isInterface()) { // 不能不是接口
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
        if (!withExtensionAnnotation(type)) { // 不能没有 SPI 标注
            throw new IllegalArgumentException("Extension type(" + type +
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }

        // 1. 通过 Car.class 从 EXTENSION_LOADERS 获取 ExtensionLoader
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            // 2. 没有则创建
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
}
  1. 由于是一次创建,所以 objectFactory 赋值的是 AdaptiveExtensionFactoryAdaptiveExtensionFactory 创建流程可以参考 『Dubbo SPI源码分析』SPI 机制分析
public class ExtensionLoader<T> {
    
    private final Class<?> type;
    private final ExtensionFactory objectFactory;// 用于依赖注入
    ...
    private ExtensionLoader(Class<?> type) {
        this.type = type;
        // 拿出 ExtensionFactory 接口的所有实现类中的 Adaptive 实现
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
}
  1. 获取了 ExtensionLoader 后,开始执行 getExtension() 获取实现的扩展类
public class CarDemo {

    public static void main(String[] args) {
        ExtensionLoader<Car> extensionLoader =
                ExtensionLoader.getExtensionLoader(Car.class);
        // 1. 获取接口的扩展类
        Car redCar = extensionLoader.getExtension("red");
       ...
    }
}
  1. 执行 getExtension() 方法时,先判断缓存实例 cachedInstances 中,是否存在创建的对象,没有的话,则执行 createExtension() 创建
public class ExtensionLoader<T> {

    // 缓存实例,每个接口的实现类对应一个实例
    private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
    ...
    public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        // 1. 尝试从缓存中获取扩展类
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    // 2. 获取不到扩展类实体,就创建,其中 name = red
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }
}
  1. 执行 createExtension() 时,先执行 getExtensionClasses() 获取所有扩展类
public class ExtensionLoader<T> {
	...
    private T createExtension(String name) {
        // 1. 执行 getExtensionClasses() 获取扩展类
        Class<?> clazz = getExtensionClasses().get(name); 
        ...
    }
}
  1. 执行 getExtensionClasses() 时,尝试先从 ExtensionLoader 尝试先从自己的缓存集合 cachedClasses 获取集合,如果没有就需要去加载文件获取
public class ExtensionLoader<T> {

    private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
    ....
    // 从所有文件里获取所有type接口的所有实现类并缓存
    private Map<String, Class<?>> getExtensionClasses() {
        // 1. 尝试从缓存集合中拿出集合
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    // 2. 没有就尝试加载文件
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
}
  1. loadExtensionClasses() 会从几个关键目录中获取对应文件解析后存入集合中返回
public class ExtensionLoader<T> {

    private final Class<?> type;
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    private String cachedDefaultName;
    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() {
        final SPI defaultAnnotation = type.getAnnotation(SPI.class); // interface org.apache.dubbo.common.extension.ExtensionFactory
        // SPI后面的值就是默认的实现的类,只能指定一个实现类
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();// 一开始 interface org.apache.dubbo.common.extension.ExtensionFactory 的 SPI 没标注默认值,
            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];
                }
            }
        }

        // 是一个 map,key 是别名,value 是具体的实现类
        // 会从不同的地方寻找接口的所有实现类,这就是扩展的实现
        // 主要会从三个地方找
        // META-INF/dubbo/
        // META-INF/dubbo/internal/
        // META-INF/services/
        Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
        // 1. 加载目录中的文件
        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; // 找到 org.apache.dubbo.common.extension.ExtensionFactory 所有的地方的实现类
    }
}
  1. loadDirectory() 先去拼接目录 + 接口名称,得到资源定位符后再去加载文件内容
public class ExtensionLoader<T> {
    ...
    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {// type:org.apache.dubbo.common.extension.ExtensionFactory
        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()) {
                    // 单个资源的url
                    java.net.URL resourceURL = urls.nextElement(); 
                    // 1. 加载文件的内容
                    loadResource(extensionClasses, classLoader, resourceURL);
                }
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

}
  1. 解析文件中的每一行内容后,通过 loadClass() 来校验和加载扩展类
public class ExtensionLoader<T> {
    ...
    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
            try {
                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) {
                                // 1. name 就是加载文件中的别名,line 就是实现类全名。加载扩展类
                                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);
                        }
                    }
                }
            } finally {
                reader.close();
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", class file: " + resourceURL + ") in " + resourceURL, t);
        }
    }
}
  1. loadClass() 首先读取的是第一行内容 red = com.luban.dubbo_spi.impl.RedCar 这时候先把类存入 cachedNames 属性中。再遍历下一行 com.luban.dubbo_spi.impl.CarWrapper 把包装类存入 cachedWrapperClasses 属性中,然后返回
  • 重点
    • 判断是否为包装类,只需要判断是否只有包含 Car.class 的构造函数
public class ExtensionLoader<T> {
    
    private final Class<?> type;
    private volatile Class<?> cachedAdaptiveClass = null;
    private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
    private final Map<String, Object> cachedActivates = new ConcurrentHashMap<String, Object>();
    ...
    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 when load extension class(interface: " +
                    type + ", class line: " + clazz.getName() + "), class "
                    + clazz.getName() + "is not subtype of interface.");
        }
        // 实现类上是否有 Adaptive 注解,这段代码的意思就是一个接口的实现类中只有一个 Adaptive
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            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());
            }
            // 2. 实现类是不是 wrapper类,判断逻辑是这个实现类的构造方法的参数是不是有且仅有一个参数,且参数类型是接口类型
        } else if (isWrapperClass(clazz)) { 
            // wrapper类可以有多个
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
            clazz.getConstructor();
            if (StringUtils.isEmpty(name)) {
                // 如果在文件里没有配名字,可以去看实现类上是否有Extension注解,可以取这个注解的值作为名字
                // 如果没有Extension这个注解,则取实现类的simple名,并进行简化,比如接口为CarService, 实现类为RedCarService, 那么名字则为red
                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 (names != null && names.length > 0) {
                ...
                // 1. red = com.luban.dubbo_spi.impl.RedCar 存入 cachedNames 缓存中
                for (String n : names) {
                    // 配了多个名字cachedName也只会缓存一个
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                    // 多个名字会产生多条记录
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                    }
                }
            }
        }
    }
    
    // 判断是否为包装类依据
    private boolean isWrapperClass(Class<?> clazz) {
        try {
            clazz.getConstructor(type);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }
}
  1. 加载完各个目录的文件后,就会得到对应的 extensionClasses 集合,并根据 name 获取到对应的类,并创建实例。因为在加载时,会把所有的包装类存入 cachedWrapperClasses 集合中,通过遍历,该实例进行包装,最后返回包装的扩展类以供使用
public class ExtensionLoader<T> {
    // 实现类对应的实例
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
    ...
    private T createExtension(String name) {
        Class<?> clazz = getExtensionClasses().get(name); // 取出对应的实现类
        if (clazz == null) {
            throw findException(name);
        }
        try {
            // 1. 生成实例并缓存
            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)) {
                // 2. 遍历所有包装类,对实例进行包装
                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 + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }
}
  1. 总结
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值