Dubbo源码学习(二) 扩展SPI原理

Dubbo扩展SPI源码剖析

SPI在功能中最重要的类就是ExtensionLoader ,它是所有Dubbo中SPI的入口。

其中最重要的是
org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoaderorg.apache.dubbo.common.extension.ExtensionLoader.getExtension 方法。
getExtensionLoader 获取扩展点加载器 并加载所对应的所有的扩展点实现
getExtension 根据name 获取扩展的指定实现

getExtensionLoader 加载过程

  1. 是如何进行实例化ExtensionLoader 的
    private static <T> boolean withExtensionAnnotation(Class<T> type) {
        // 包含`@SPI`注解在接口上
        return type.isAnnotationPresent(SPI.class);
    }

    @SuppressWarnings("unchecked")
    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() + "!");
        }
        // 尝试从缓存中加载
        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;
    }

  1. 具体看一下ExtensionLoader 的构造器函数, 这里他的实现比较简单,并没有做太多的操作。主要是对type进行赋值操作,然后获取ExtensionFactory 对象。
    private ExtensionLoader(Class<?> type) {
        this.type = type;
        // 创建ExtensionFactory对象,ExtensionFactory也是一个SPI扩展点
        // adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
        // spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

在这里插入图片描述

  1. 具体再来关注一下ExtensionFactory是做什么用的, 从这里可以大概的看出来,他是通过传入扩展点类型和真正的名称来获取扩展的。这里就和SPI中的具体名称实现相挂钩,它的两个默认实现类就是上图中的,保存在dubbo-common/src/main/resources/METAINF/ dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory文件中。
/**
 * ExtensionFactory
 * 根据传入的扩展点类型和名字 来获取扩展 这里和SPI中的具体实现建立联系
 */
@SPI
public interface ExtensionFactory {

    /**
     * Get extension.
     *
     * @param type object type.
     * @param name object name.
     * @return object instance.
     */
    <T> T getExtension(Class<T> type, String name);

}

  1. 可以看到在AdaptiveExtensionFactory 中是使用@Adaptive 标记的。这里可以通过类名基本看出来,他其实最主要的作用是进行代理其他的ExtensionFactory。其中比较重要的方法在于getSupportedExtensions 方法,获取所有支持的扩展信息实现。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        // 获取针对ExtensionFactory的扩展加载器
        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;
    }

}
  1. 获取所有支持的扩展信息实现: ExtensionLoader.getSupportedExtensions ,这里可以看到,其实比较关键的方法在于getExtensionClasses 方法
    public Set<String> getSupportedExtensions() {
        // 保存扩展类的信息,name 和 class 对应
        Map<String, Class<?>> clazzes = getExtensionClasses();
        // 返回所有的扩展点名称
        return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
    }
  1. 观察getExtensionClasses 的实现,可以看到这里其实主要做的就是一件事情,防止重复被加载,所以真正的的实现还需要专门去查看loadExtensionClasses 方法在我们通过名称获取扩展类之前,首先需要根据配置文件解析出扩展类名称到扩展类的映射关系表classes之后再根据扩展项名称 从映射关系表中获取取对应的扩展类即可。相关过程代码分析如下
    private Map<String, Class<?>> getExtensionClasses() {
        // 先从缓存中获取已经加载的扩展类
        Map<String, Class<?>> classes = cachedClasses.get();
        // 双重检查
        if (classes == null) {
            // 同步方法,找不到classes锁住,防止重复加载
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    // 加载扩展类信息并缓存
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }
  1. 观察loadExtensionClasses 方法实现。这里主要做了两件事情。1: 加载当前SPI的默认实现。2:加载这个类的所有扩展点实现,并且按照name和Class对象的形式存储,下面会专门针对于cacheDefaultExtensionNameloadDirectory 方法做说明
    /**
     * synchronized in getExtensionClasses
     */
    private Map<String, Class<?>> loadExtensionClasses() {
        // 加载默认的扩展实现,也就是@SPI注解中的值
        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;
    }

这里的strategies是通过JDK的SPI机制读取到具体路径为dubbo-dubbo-2.7.8\dubbo-common\src\main\resources\META-INF\services\org.apache.dubbo.common.extension.LoadingStrategy,实现类有三个
org.apache.dubbo.common.extension.DubboInternalLoadingStrategy
org.apache.dubbo.common.extension.DubboLoadingStrategy
org.apache.dubbo.common.extension.ServicesLoadingStrategy
代码如下:

    private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();

    /**
     * Load all {@link Prioritized prioritized} {@link LoadingStrategy Loading Strategies} via {@link ServiceLoader}
     *
     * @return non-null
     * @since 2.7.7
     */
    private static LoadingStrategy[] loadLoadingStrategies() {
        // 通过SPI机制读取LoadingStrategy实现类
        return stream(load(LoadingStrategy.class).spliterator(), false)
                .sorted()
                .toArray(LoadingStrategy[]::new);
    }

观察cacheDefaultExtensionName 方法实现。这里面的是实现比较简单,主要用于读取注解中value值来获取到默认的名称。

    private void cacheDefaultExtensionName() {
        // 获取当前类是否包含SPI注解,如果没有@SPI注解则返回
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation == null) {
            return;
        }

        // 获取默认的扩展名,也就是在@SPI中的 value值
        // 比如LoadBalance的默认实现就是random 就是通过这里读取
        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];
            }
        }
    }

观察loadDirectory 方法实现。这里的主要功能是从这个文件夹中寻找真正的文件列表,并且对其中的文件内容解析并且放入到extensionClasses Map中,具体解析文件的内容实现,还要参考loadResource 实现。

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
                               boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
        // 文件名规则:路径/包名.接口名
        String fileName = dir + type;
        try {
            // 寻找classloader和url列表
            Enumeration<java.net.URL> urls = null;
            ClassLoader classLoader = findClassLoader();

            // try to load from ExtensionLoader's ClassLoader first
            // 如果需要的话, 需要先从当前类的ClassLoader中寻找
            if (extensionLoaderClassLoaderFirst) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();
                if (ClassLoader.getSystemClassLoader() != extensionLoaderClassLoader) {
                    urls = extensionLoaderClassLoader.getResources(fileName);
                }
            }

            // 如果找不到任何的URL列表,则继续尝试去其当前线程的ClassLoader中寻找
            if (urls == null || !urls.hasMoreElements()) {
                if (classLoader != null) {
                    urls = classLoader.getResources(fileName);
                } else {
                    urls = ClassLoader.getSystemResources(fileName);
                }
            }

            // 遍历每一个资源文件,并且进行加载资源信息到extensionClasses, 主要功能是读取文件内容
            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);
        }
    }
  1. 进行观察loadResource 实现,主要是用于读取文件操作,并且将方法交由loadClass 来加载类信息。加载类信息也是最重要的方法所在。
    private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
                              java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
        try {
            // 根据resourceURL读取文件
            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) {
                                // 加载 key = value 形式的数据
                                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);
        }
    }
  1. 观察loadClass 类的实现,可以看到这里是最终进行完成类映射的地方。关于Adaptive中的类实现原理后续会再跟进。
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        // 当前扩展点必须是对接口的实现, 接口就是要通过ExtensionLoader读取的
        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.");
        }
        // 如果包含了@Adaptive ,就存储到 cachedAdaptiveClass
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
        } else if (isWrapperClass(clazz)) {
            // 判断是否是wapper类型, 是否构造函数中有该接口类型的传入
            // wrapper类型的意思是,对当前的扩展点实现封装功能处理
            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);
                }
            }

            // 对name和class做映射
            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
                // 如果当前类有 @Activate注解,加入cacheActivateClass中
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    // 缓存名称
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, n, overridden);
                }
            }
        }
    }

当执行完这几个方法之后,会对以下几个字段进行更新:

  • cachedAdaptiveClass: 当前Extension类型对应的AdaptiveExtension类型(只能一个)
  • cachedWrapperClasses: 当前Extension类型对应的所有Wrapper实现类型(无顺序)
  • cachedActivates: 当前Extension实现自动激活实现缓存(map,无序)
  • cachedNames: 扩展点实现类对应的名称(如配置多个名称则值为第一个)

根据name获取扩展点的方法 getExtension

  1. getExtension 方法实现。这里面同样主要作用是根据name对扩展点进行处理和进行加锁来创建真实的引用,其中都是有使用缓存来处理。
    public T getExtension(String name, boolean wrap) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        }
        // 获取当前SPi的默认扩展实现类
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        // 获取当前类的Holder, 建立一个引用,判断加锁
        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;
    }

在这里插入图片描述

  1. 下面来看看getOrCreateHolder 是如何保证缓存的
    private Holder<Object> getOrCreateHolder(String name) {
        // 根据当前的名称从缓存中获取
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            // 如果不存在的话,则使用putIfAbsent的原子操作来设置值,这个值可以保证多线程的情况下有值的时候不处理,没有值进行保存
            cachedInstances.putIfAbsent(name, new Holder<>());
            // 获取真实的holder处理器
            holder = cachedInstances.get(name);
        }
        return holder;
    }
  1. 然后我们再来看看createExtension 的实现,他是具体根据扩展的class名称来进行创建实例的类。这里也是创建扩展点类的主要实现。下面我们也对其他扩展点注册的方法做说明。
    private T createExtension(String name, boolean wrap) {
        // 从已经加载好的集合中,根据name获取对应的class对象
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            // 获取实例
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                // 如果不存在这个扩展的实例,使用反射创建一个实例对象放入 EXTENSION_INSTANCES
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
            // 注入其他的扩展,用于和其他的扩展点互通,  给当前的扩展点设置其他需要的扩展点
            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);
        }
    }

在这里插入图片描述

  1. injectExtension 方法观察
    private T injectExtension(T instance) {

        if (objectFactory == null) {
            return instance;
        }

        try {
            // 遍历其中的所有方法
            for (Method method : instance.getClass().getMethods()) {
                // 是否是set方法
                // 1. 以"set"开头
                // 2. 参数长度为1
                // 3. 是public的方法
                if (!isSetter(method)) {
                    continue;
                }
                /**
                 * Check {@link DisableInject} to see if we need auto injection for this property
                 */
                // 如果设置了取消注册,则不进行处理
                if (method.getAnnotation(DisableInject.class) != null) {
                    continue;
                }
                // 获取参数类型,并且非基础类型(String, Integer等类型)
                Class<?> pt = method.getParameterTypes()[0];
                if (ReflectUtils.isPrimitives(pt)) {
                    continue;
                }

                try {
                    // 获取需要set的扩展点名称
                    String property = getSetterProperty(method);
                    // 从objectFactory得到指定的扩展点
                    Object object = objectFactory.getExtension(pt, property);
                    if (object != null) {
                        // 比如一个set方法,setRandom(LoadBalance loadBalance)
                        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;
    }

Adaptive功能实现原理

Adaptive的主要功能是对所有的扩展点进行封装为一个类,通过URL传入参数的时动态选择需要使用的扩展点。其底层的实现原理就是动态代理,这里我们会通过源码的形式告诉大家,他是如何通过动态代理进行加载的。

  1. 这里从getAdaptiveExtension 方法讲起,这个里面就是真正获取该类。这里可以看到,ExtentionLoader 中大量的使用了Holder和加锁的方式去进行唯一创建
    public T getAdaptiveExtension() {
        // 和原先是用相同的方式,进行Holder和加锁的方式来保证只会被创建一次
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            // 如果直接已经有创建并且错误的情况,则直接返回错误信息,防止重复没必要的创建
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }

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

        return (T) instance;
    }

  1. 这里继续从createAdaptiveExtension 来去查看实现。这里主要是进行了一些方法封装。
    private T createAdaptiveExtension() {
        try {
            // 这里使用`getAdaptiveExtensionClass`方法进行构建类并且执行实例化
            // 然后和普通的其他class相同,依旧使用injectExtension进行扩展
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

    private Class<?> getAdaptiveExtensionClass() {
        // 确保已经加载了所有的扩展类信息
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            // 如果已经加载过了,则直接返回
            return cachedAdaptiveClass;
        }
        // 否则进行构建操作
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
  1. 具体再来看createAdaptiveExtensionClass 方法。这里主要是进行生成Adaptive的代码,并且进行编译生成class。
    private Class<?> createAdaptiveExtensionClass() {
        // 实例化一个新的Adaptive的代码生成器,并且进行代码生成
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        // 获取类加载器
        ClassLoader classLoader = findClassLoader();
        // 通过扩展点,寻找编译器, 目前有Java自带的编译器和Javassist的编译器
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        // 编译并且生成class
        return compiler.compile(code, classLoader);
    }

具体生成的代码文件

package com.elvis.service;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class HelloService$Adaptive implements com.elvis.service.HelloService {
public java.lang.String sayHello()  {
throw new UnsupportedOperationException("The method public abstract java.lang.String com.elvis.service.HelloService.sayHello() of interface com.elvis.service.HelloService is not adaptive method!");
}
public java.lang.String sayHello(org.apache.dubbo.common.URL arg0)  {
if (arg0 == null) throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("hello.service", "human");
if(extName == null) throw new IllegalStateException("Failed to get extension (com.elvis.service.HelloService) name from url (" + url.toString() + ") use keys([hello.service])");
com.elvis.service.HelloService extension = (com.elvis.service.HelloService)ExtensionLoader.getExtensionLoader(com.elvis.service.HelloService.class).getExtension(extName);
return extension.sayHello(arg0);
}
}

在这里插入图片描述

  1. 具体通过AdaptiveClassLoaderCodeGenerator.generate 方法来进行实现真正的代码生成
    public String generate() {
        // no need to generate adaptive class since there's no adaptive method found.
        // 如果没有任何方法标记为Adaptive,则不做处理
        if (!hasAdaptiveMethod()) {
            throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
        }
        // 进行编写代码
        StringBuilder code = new StringBuilder();
        // 生成包信息
        code.append(generatePackageInfo());
        // 生成引用信息
        code.append(generateImports());
        // 生成类声明
        code.append(generateClassDeclaration());

        // 生成每一个方法
        Method[] methods = type.getMethods();
        for (Method method : methods) {
            code.append(generateMethod(method));
        }
        // 输出最后的一个"}"来结束当前类
        code.append("}");

        if (logger.isDebugEnabled()) {
            logger.debug(code.toString());
        }
        return code.toString();
    }
  1. 这里主要对其中的每一个方法来做处理。具体主要观看generateMethod方法。这里的很多方法主要是依赖反射机制去进行方法封装,最终拼接为一个最终字符串。其中最关键的方法在于generateMethodContent方法来生成代理功能。
    private String generateMethod(Method method) {
        // 方法返回类型
        String methodReturnType = method.getReturnType().getCanonicalName();
        // 方法名称
        String methodName = method.getName();
        // 生成方法内容
        String methodContent = generateMethodContent(method);
        // 生辰参数列表
        String methodArgs = generateMethodArguments(method);
        // 方法抛出的异常
        String methodThrows = generateMethodThrows(method);
        // 格式化为一个字符串
        // public %s %s(%s) %s {
        // %s
        // }
        return String.format(CODE_METHOD_DECLARATION, methodReturnType, methodName, methodArgs, methodThrows, methodContent);
    }
  1. generateMethodContent 方法解读。这块儿更推荐通过debug的形式走进来, 看代码也更直接了当(就可以直接按照常用功能中的SPI章节来debug)。这部分也是整个Adaptive中最为核心的代码,包括获取扩展点名称并且执行。
    private String generateMethodContent(Method method) {
        // 获取Adaptive注解,只支持含有Adaptive注解方法处理
        Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
        StringBuilder code = new StringBuilder(512);
        if (adaptiveAnnotation == null) {
            // 没有该注解,直接抛出异常
            return generateUnsupported(method);
        } else {
            // 获取URL参数的所在位置
            int urlTypeIndex = getUrlTypeIndex(method);

            // found parameter in URL type
            if (urlTypeIndex != -1) {
                // Null Point check
                // 增加判断url不为空的代码
                code.append(generateUrlNullCheck(urlTypeIndex));
            } else {
                // 获取这个方法中的所有参数列表
                // 寻找每个参数中是否有"get"开头的方法,并且返回值是URL的
                // 如果有则同样认定为找到,否则抛出异常
                // did not find parameter in URL type
                code.append(generateUrlAssignmentIndirectly(method));
            }
            // 获取扩展点的适配名称
            String[] value = getMethodAdaptiveValue(adaptiveAnnotation);

            // 判断是否有参数是Invocation类
            // 这里判断的主要目的在于,拥有Invocation时,则获取扩展名称的方式发生改变
            // 存在Invocation时,通过getMethodParameter,否则通过getParameter来执行
            // getMethodParameter是dubboURL中特有的,用于将"test.a"转换为"testA"的形式
            boolean hasInvocation = hasInvocationArgument(method);

            // 增加有Invocation类时的不为空判断
            code.append(generateInvocationArgumentNullCheck(method));

            // 生成获取扩展点名称的方法
            code.append(generateExtNameAssignment(value, hasInvocation));
            // check extName == null?
            // 检查扩展点不能为空
            code.append(generateExtNameNullCheck(value));
            // 获取扩展点实现
            code.append(generateExtensionAssignment());

            // return statement
            // 返回扩展点中的真实调用
            code.append(generateReturnAndInvocation(method));
        }

        return code.toString();
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值