我的架构梦:(二十七)Dubbo源码分析之扩展SPI源码剖析

Dubbo源码分析之扩展SPI源码剖析

    • 一、getExtensionLoader 加载过程
    • 二、 根据name获取扩展点的方法 getExtension
    • 三、Adaptive功能实现原理

基于Dubbo SPI加载机制,让整个框架的接口和具体实现完全解耦,从而奠定了整个框架良好可扩展性的基础。SPI的底层最重要的类就是ExtensionLoader,它是所有DubboSPI的入口。

我们下面就来分析ExtensionLoader是怎么加载的,这里会具体介绍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);
}

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    if (type == null) { // 必须传入类型
        throw new IllegalArgumentException("Extension type == null");
    } else if (!type.isInterface()) { // 必须是接口类型
        throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
    } else if (!withExtensionAnnotation(type)) { // 必须包含SPI的注解
        throw new IllegalArgumentException("Extension type (" + type + ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
    } else {
    	// 尝试从已经加载过的数据中去读取(缓存功能)
        ExtensionLoader<T> loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
        if (loader == null) {
        	// 如果没有的话,才会进行初始化,并且放入到缓存汇总
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
            loader = (ExtensionLoader)EXTENSION_LOADERS.get(type);
        }

        return loader;
    }
}

2、具体看一下 ExtensionLoader 的构造器函数, 这里他的实现比较简单,并没有做太多的操作。主要是对type进行赋值操作,然后获取 ExtensionFactory 对象。

private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 这里需要对对象的工厂做额外的创建,可以看到扩展的工厂也是一个扩展点
    this.objectFactory = type == ExtensionFactory.class ? null : (ExtensionFactory)getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension();
}

3、具体再来关注一下是做什么用的,,从这里我们可以大概的看出来,他是通过传入扩展点类型和真正的名称来获取扩展的。这里就和我们SPI中的具体名称实现相挂钩。

@SPI
public interface ExtensionFactory {
    <T> T getExtension(Class<T> var1, String var2);
}

4、可以在

dubbo-common/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension/ExtensionFactory 

中看到,他默认有三个实现的提供

spring=org.apache.dubbo.config.spring.extension.SpringExtensionFactory
adaptive=org.apache.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=org.apache.dubbo.common.extension.factory.SpiExtensionFactory

5、可以看到在中是使用 标记的。这里可以通过类名基本看出来,他其实最主要的作用是进行代理其他的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();
        // 获取支持的扩展
        Iterator var3 = loader.getSupportedExtensions().iterator();

        while(var3.hasNext()) {
            String name = (String)var3.next();
            // 将所有的ExtensionFactory进行缓存
            list.add(loader.getExtension(name));
        }

        this.factories = Collections.unmodifiableList(list);
    }

    public <T> T getExtension(Class<T> type, String name) {
        Iterator var3 = this.factories.iterator();

        Object extension;
        do {
            if (!var3.hasNext()) {
                return null;
            }

            ExtensionFactory factory = (ExtensionFactory)var3.next();
            // 交给每个真实的ExtensionFactory来处理
            extension = factory.getExtension(type, name);
        } while(extension == null);

        return extension;
    }
}

6、获取所有支持的扩展信息实现: ExtensionLoader.getSupportedExtensions ,这里可以看到,其实比较关键的方法在于 getExtensionClasses 方法

public Set<String> getSupportedExtensions() {
	// 获取所有的扩展类信息
    Map<String, Class<?>> clazzes = this.getExtensionClasses();
    // 返回所有的扩展点名称
    return Collections.unmodifiableSet(new TreeSet(clazzes.keySet()));
}

7、观察 getExtensionClasses 的实现,可以看到这里其实主要做的就是一件事情,防止重复被加 载,所以真正的的实现还需要专门去查看 loadExtensionClasses 方法,在我们通过名称获取扩展类之前,首先需要根据配置文件解析出扩展类名称到扩展类的映射关系表 classes之后再根据扩展项名称从映射关系表中获取取对应的扩展类即可。相关过程代码分析如下:

private Map<String, Class<?>> getExtensionClasses() {
	// 从缓存中获取已加载的扩展类
    Map<String, Class<?>> classes = (Map)this.cachedClasses.get();
    // 双重检查
    if (classes == null) {
    	// 为空的话,则锁住,标识只会被执行一次
        synchronized(this.cachedClasses) {
            classes = (Map)this.cachedClasses.get();
            if (classes == null) {
            	// 进行加载信息 加载扩展类
                classes = this.loadExtensionClasses();
                this.cachedClasses.set(classes);
            }
        }
    }

    return classes;
}

8、观察方法实现。这里主要做了两件事情。1: 加载当前SPI的默认实现。2: 加载这个类的所有扩展点实现,并且按照nameClass对象的形式存储,下面会专门针对于
cacheDefaultExtensionNameloadDirectory 方法做说明

private Map<String, Class<?>> loadExtensionClasses() {
	// 加载默认扩展的实现名称
    this.cacheDefaultExtensionName();
    // 获取其中每一种实现的名称和对应的classes
	// 具体的目录请参照下面的所有目录
    Map<String, Class<?>> extensionClasses = new HashMap();
    this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName(), true);
    this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName().replace("org.apache", "com.alibaba"), true);
    this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName());
    this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName().replace("org.apache", "com.alibaba"));
    this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName());
    this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName().replace("org.apache", "com.alibaba"));
    return extensionClasses;
}

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

private void cacheDefaultExtensionName() {
	// 获取当前类是否包含SPI注解,一般走到这里都是拥有这个注解的
    SPI defaultAnnotation = (SPI)this.type.getAnnotation(SPI.class);
    if (defaultAnnotation != null) {
    	// 来获取其的value值,这个值主要的作用是设置这个SPI中的默认扩展名 
    	// 比如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 " + this.type.getName() + ": " + Arrays.toString(names));
            }

            if (names.length == 1) {
                this.cachedDefaultName = names[0];
            }
        }

    }
}

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

private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type, boolean extensionLoaderClassLoaderFirst) {
	// 文件名称规则: 路径/包名.接口名
    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);
            }
        }
		// 如果存在文件的话
        if (urls != null) {
            while(urls.hasMoreElements()) {
            	// 遍历每一个资源文件,并且进行加载资源信息到extensionClasses, 主要功能是读取文件内容
                java.net.URL resourceURL = (java.net.URL)urls.nextElement();
                this.loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } catch (Throwable var9) {
        logger.error("Exception occurred when loading extension class (interface: " + type + ", description file: " + fileName + ").", var9);
    }

}

9、进行观察 loadResource 实现,主要是用于读取文件操作,并且将方法交由 loadClass 来加载类信息。加载类信息也是最重要的方法所在。

private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
    try {
    	// 读取文件
        BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8));
        Throwable var5 = null;

        try {
            String line;
            try {
                while((line = reader.readLine()) != null) {
                	// 截取文件#前面的内容
                    int ci = line.indexOf(35);
                    if (ci >= 0) {
                        line = line.substring(0, ci);
                    }

                    line = line.trim();
                    // 如果有内容的话
                    if (line.length() > 0) {
                        try {
                        	// 则进行加载key=value的形式数据
                            String name = null;
                            int i = line.indexOf(61);
                            if (i > 0) {
                                name = line.substring(0, i).trim();
                                line = line.substring(i + 1).trim();
                            }

                            if (line.length() > 0) {
                            	// 对类信息进行加载操作
                                this.loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                            }
                        } catch (Throwable var19) {
                            IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + this.type + ", class line: " + line + ") in " + resourceURL + ", cause: " + var19.getMessage(), var19);
                            this.exceptions.put(line, e);
                        }
                    }
                }
            } catch (Throwable var20) {
                var5 = var20;
                throw var20;
            }
        } finally {
            if (reader != null) {
                if (var5 != null) {
                    try {
                        reader.close();
                    } catch (Throwable var18) {
                        var5.addSuppressed(var18);
                    }
                } else {
                    reader.close();
                }
            }

        }
    } catch (Throwable var22) {
        logger.error("Exception occurred when loading extension class (interface: " + this.type + ", class file: " + resourceURL + ") in " + resourceURL, var22);
    }

}

10、观察 loadClass 类的实现,可以看到这里是最终进行完成类映射的地方。关于Adaptive中的类实现原理,我们放在这个章节中的偏后面进行细讲。

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
	// 当前扩展点的实现,必须是当前扩展接口的实现才可以
    if (!this.type.isAssignableFrom(clazz)) {
        throw new IllegalStateException("Error occurred when loading extension class (interface: " + this.type + ", class line: " + clazz.getName() + "), class " + clazz.getName() + " is not subtype of interface.");
    } else {
    	// 如果是包含了Adaptive注解,则认为是需要对扩展点包装的方法,这里只做了存储操作,存储至 cachedAdaptiveClass中
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            this.cacheAdaptiveClass(clazz);
        } else if (this.isWrapperClass(clazz)) {
        	// 判断是否是wapper类型, 是否构造函数中有该接口类型的传入 
        	// wrapper类型的意思是,对当前的扩展点实现封装功能处理
            this.cacheWrapperClass(clazz);
        } else {
            clazz.getConstructor();
            // 寻找他是否已经定义过了名称, 这里就不继续往里面细看了,主要是获取当前类的org.apache.dubbo.common.Extension注解,如果有的话就使用这个名称,否则的话就是用当前类的简单名称
            if (StringUtils.isEmpty(name)) {
                name = this.findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
                }
            }
			// 否则的话,就对这个名称和class做映射关系
            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
            	// 如果当前类拥有Activate注解,则将其进行添加到cachedActivates对象中,意味着需要执行
                this.cacheActivateClass(clazz, names[0]);
                String[] var6 = names;
                int var7 = names.length;
				// 进行名称映射保存
                for(int var8 = 0; var8 < var7; ++var8) {
                    String n = var6[var8];
                    this.cacheName(clazz, n);
                    this.saveInExtensionClass(extensionClasses, clazz, n);
                }
            }
        }

    }
}

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

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

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

1、getExtension 方法实现。这里面同样主要作用是根据name对扩展点进行处理和进行加锁来创建真实的引用,其中都是有使用缓存来处理。

public T getExtension(String name) {
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    } else if ("true".equals(name)) { // 获取当前SPi的默认扩展实现类
        return this.getDefaultExtension();
    } else {
    	// 获取当前类的holder,实现原理和cachedClasses的方式相同,都是建立同一个引用后再进行 加锁
        Holder<Object> holder = this.getOrCreateHolder(name);
        Object instance = holder.get();
        if (instance == null) {
            synchronized(holder) {
                instance = holder.get();
                if (instance == null) {
                	// 真正进行创建实例
                    instance = this.createExtension(name);
                    holder.set(instance);
                }
            }
        }

        return instance;
    }
}

2、下面来看看 getOrCreateHolder 是如何保证缓存的。

private Holder<Object> getOrCreateHolder(String name) {
	// 获取当前名称的和对象Holder的映射关系
    Holder<Object> holder = (Holder)this.cachedInstances.get(name);
    if (holder == null) {
    	// 如果不存在的话,则使用putIfAbsent的原子操作来设置值,这个值可以保证多线程的额情 况下有值的时候不处理,没有值进行保存
        this.cachedInstances.putIfAbsent(name, new Holder());
        // 获取真实的holder处理器
        holder = (Holder)this.cachedInstances.get(name);
    }

    return holder;
}

3、然后我们再来看看 createExtension 的实现,他是具体根据扩展的class名称来进行创建实例的类。这里也是创建扩展点类的主要实现。下面我们也对其他扩展点注册的方法做说明。

private T createExtension(String name) {
	// 从配置文件中加载所有的扩展类 可以得到配置项名称 到配置类的映射关系
    Class<?> clazz = (Class)this.getExtensionClasses().get(name);
    if (clazz == null) {
        throw this.findException(name);
    } else {
        try {
        	// 获取是否已经有实例了
            T instance = EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
            	// 没有的话,同样适用putIfAbsent的方式来保证只会创建一个对象并且保存
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = EXTENSION_INSTANCES.get(clazz);
            }
			// 注入其他扩展点的实体,用于扩展点和其他的扩展点相互打通
            this.injectExtension(instance);
            // 进行遍历所有的包装类信息,分别对包装的类进行包装实例化,并且返回自身引用
            Set<Class<?>> wrapperClasses = this.cachedWrapperClasses;
            Class wrapperClass;
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
            	// 同样进行注册其他扩展点的功能
                for(Iterator var5 = wrapperClasses.iterator(); var5.hasNext(); instance = this.injectExtension(wrapperClass.getConstructor(this.type).newInstance(instance))) {
                    wrapperClass = (Class)var5.next();
                }
            }
			// 对扩展点进行初始化操作
            this.initExtension(instance);
            return instance;
        } catch (Throwable var7) {
            throw new IllegalStateException("Extension instance (name: " + name + ", class: " + this.type + ") couldn't be instantiated: " + var7.getMessage(), var7);
        }
    }
}

4、 injectExtension 方法观察

private T injectExtension(T instance) {
    if (this.objectFactory == null) {
        return instance;
    } else {
        try {
        	// 遍历其中的所有方法
            Method[] var2 = instance.getClass().getMethods();
            int var3 = var2.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                Method method = var2[var4];
                // 是否是set方法
				// 1. 以"set"开头
				// 2. 参数长度为1
				// 3. 是公开的方法
				// 如果设置了取消注册,则不进行处理
                if (this.isSetter(method) && method.getAnnotation(DisableInject.class) == null) {	
                	// 获取参数类型,并且非基础类型(String, Integer等类型)
                    Class<?> pt = method.getParameterTypes()[0];
                    if (!ReflectUtils.isPrimitives(pt)) {
                        try {
                        	// 获取需要set的扩展点名称
                            String property = this.getSetterProperty(method);
                            // 从ExtensionLoader中加载指定的扩展点
							// 比如有一个方法为setRandom(LoadBalance loadBalance),那么则以为着需要加载负载均衡中名为random的扩展点
                            Object object = this.objectFactory.getExtension(pt, property);
                            if (object != null) {
                                method.invoke(instance, object);
                            }
                        } catch (Exception var9) {
                            logger.error("Failed to inject via method " + method.getName() + " of interface " + this.type.getName() + ": " + var9.getMessage(), var9);
                        }
                    }
                }
            }
        } catch (Exception var10) {
            logger.error(var10.getMessage(), var10);
        }

        return instance;
    }
}

三、Adaptive功能实现原理

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

1、这里我们 getAdaptiveExtension 方法讲起,这个里面就是真正获取该类。这里可以看到, ExtentionLoader 中大量的使用了Holder和加锁的方式去进行唯一创建。

public T getAdaptiveExtension() {
	// 和原先是用相同的方式,进行Holder和加锁的方式来保证只会被创建一次
    Object instance = this.cachedAdaptiveInstance.get();
    if (instance == null) {
    	// 如果直接已经有创建并且错误的情况,则直接返回错误信息,防止重复没必要的创建
        if (this.createAdaptiveInstanceError != null) {
            throw new IllegalStateException("Failed to create adaptive instance: " + this.createAdaptiveInstanceError.toString(), this.createAdaptiveInstanceError);
        }

        synchronized(this.cachedAdaptiveInstance) {
            instance = this.cachedAdaptiveInstance.get();
            if (instance == null) {
                try {
                	// 这里真实的进行创建操作
                    instance = this.createAdaptiveExtension();
                    this.cachedAdaptiveInstance.set(instance);
                } catch (Throwable var5) {
                    this.createAdaptiveInstanceError = var5;
                    throw new IllegalStateException("Failed to create adaptive instance: " + var5.toString(), var5);
                }
            }
        }
    }

    return instance;
}

2、这里我们继续从createAdaptiveExtension 来去查看实现。这里主要是进行了一些方法封装。

private T createAdaptiveExtension() {
    try {
        return this.injectExtension(this.getAdaptiveExtensionClass().newInstance());
    } catch (Exception var2) {
        throw new IllegalStateException("Can't create adaptive extension " + this.type + ", cause: " + var2.getMessage(), var2);
    }
}
private Class<?> getAdaptiveExtensionClass() {
	// 确保已经加载了所有的扩展类信息
    this.getExtensionClasses();
    // 如果已经加载过了,则直接返回
    // 否则进行构建操作
    return this.cachedAdaptiveClass != null ? this.cachedAdaptiveClass : (this.cachedAdaptiveClass = this.createAdaptiveExtensionClass());
}

3、具体再来看 createAdaptiveExtensionClass 方法。这里主要是进行生成Adaptive的代码,并且进行编译生成class

private Class<?> createAdaptiveExtensionClass() {
	// 实例化一个新的Adaptive的代码生成器,并且进行代码生成
    String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
    // 获取类加载器
    ClassLoader classLoader = findClassLoader();
    // 通过扩展点,寻找编译器, 目前有Java自带的编译器和Javassist的编译器,这里不做细展开
    Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
    // 编译并且生成class
    return compiler.compile(code, classLoader);
}

4、具体通过 AdaptiveClassLoaderCodeGenerator.generate 方法来进行实现真正的代码生成。

public String generate() {
	// 如果没有任何方法标记为Adaptive,则不做处理
    if (!this.hasAdaptiveMethod()) {
        throw new IllegalStateException("No adaptive method exist on extension " + this.type.getName() + ", refuse to create the adaptive class!");
    } else {
    	// 进行编写代码
        StringBuilder code = new StringBuilder();
        // 生成包信息
        code.append(this.generatePackageInfo());
        // 生成引用信息
        code.append(this.generateImports());
        // 生成类声明
        code.append(this.generateClassDeclaration());
        // 生成每一个方法
        Method[] methods = this.type.getMethods();
        Method[] var3 = methods;
        int var4 = methods.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Method method = var3[var5];
            code.append(this.generateMethod(method));
        }
		// 输出最后的一个"}"来结束当前类
        code.append("}");
        if (logger.isDebugEnabled()) {
            logger.debug(code.toString());
        }

        return code.toString();
    }
}

5、这里主要对其中的每一个方法来做处理。具体主要观看 generateMethod 方法。这里的很多方法主要是依赖反射机制去进行方法封装,最终拼接为一个最终字符串。其中最关键的方法在于
generateMethodContent 方法来生成代理功能。

private String generateMethod(Method method) {
	// 方法返回类型
    String methodReturnType = method.getReturnType().getCanonicalName();
    // 方法名称
    String methodName = method.getName();
    // 生成方法内容
    String methodContent = this.generateMethodContent(method);
    // 生辰参数列表
    String methodArgs = this.generateMethodArguments(method);
    // 方法抛出的异常
    String methodThrows = this.generateMethodThrows(method);
    // 格式化为一个字符串
    return String.format("public %s %s(%s) %s {\n%s}\n", methodReturnType, methodName, methodArgs, methodThrows, methodContent);
}

6、 generateMethodContent 方法解读。这块儿更推荐通过debug的形式走进来, 看代码也更直接了当(就可以直接按照常用功能中的SPI章节来debug)。这部分也是整个Adaptive中最为核心的代码,包括获取扩展点名称并且执行。

private String generateMethodContent(Method method) {
	// 获取Adaptive注解,只支持含有Adaptive注解方法处理
    Adaptive adaptiveAnnotation = (Adaptive)method.getAnnotation(Adaptive.class);
    StringBuilder code = new StringBuilder(512);
    if (adaptiveAnnotation == null) {
    	// 没有该注解,直接抛出异常
		// throw new UnsupportedOperationException
        return this.generateUnsupported(method);
    } else {
    	// 获取URL参数的所在位置
        int urlTypeIndex = this.getUrlTypeIndex(method);
        if (urlTypeIndex != -1) {
        	// 增加判断url不为空的代码
            code.append(this.generateUrlNullCheck(urlTypeIndex));
        } else {
        	// 获取这个方法中的所有参数列表
			// 寻找每个参数中是否有"get"开头的方法,并且返回值是URL的
			// 如果有则同样认定为找到,否则抛出异常
            code.append(this.generateUrlAssignmentIndirectly(method));
        }
		// 获取扩展点的适配名称
        String[] value = this.getMethodAdaptiveValue(adaptiveAnnotation);
        // 判断是否有参数是Invocation类
		// 这里判断的主要目的在于,拥有Invocation时,则获取扩展名称的方式发生改变
		// 存在Invocation时,通过getMethodParameter,否则通过getParameter来执行
		// getMethodParameter是dubboURL中特有的,用于将"test.a"转换为"testA"的形式
        boolean hasInvocation = this.hasInvocationArgument(method);
        // 增加有Invocation类时的不为空判断
        code.append(this.generateInvocationArgumentNullCheck(method));
        // 生成获取扩展点名称的方法
        code.append(this.generateExtNameAssignment(value, hasInvocation));
        // 检查扩展点不能为空
        code.append(this.generateExtNameNullCheck(value));
        // 获取扩展点实现
        code.append(this.generateExtensionAssignment());
        // 返回扩展点中的真实调用
        code.append(this.generateReturnAndInvocation(method));
        return code.toString();
    }
}

你可能感兴趣的:(我的架构梦)