Dubbo源码解析-SPI的应用

前言:

    Dubbo中大量使用了SPI的技术,实现各调用层之间的解耦。所以,了解SPI技术的实现还是很有必要的。

    JDK本身也有SPI的实现,Dubbo对该技术实现了增强。

1.SPI

    SPI(Service Provider Interface),是java提供的一套用来被第三方实现或扩展的接口。而SPI技术就是用来查找这些扩展实现。

    概念相对比较难懂,读者可以参考这篇博文(笔者是没太读懂):https://www.cnblogs.com/happyframework/archive/2013/09/17/3325560.html 

    我们直接上示例,示例相对更好明白些。

2.JDK的SPI

2.1 提供接口和一个实现类

// Teacher
package xw.demo.adaptive;
public interface Teacher {
    void say();
}

// 实现类,提供三个实现类
package xw.demo.adaptive;
public class ChineseTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("chinese");
    }
}

public class EnglishTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("english");
    }
}

public class MathTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("math");
    }
}

2.2 创建文件

    在当前项目resources目录下 新建META-INF/services目录,并在这个目录创建一个与接口全限定名一致的文件(即xw.demo.adaptive.Teacher),文件内容为实现类的全限定名。如下所示

 

2.3 ServiceLoader加载

ServiceLoader<Teacher> teachers = ServiceLoader.load(Teacher.class);
for(Teacher t : teachers) {
    t.say();
}
// 结果为:
chinese
math
english

看结果值,我们知道ServiceLoader加载了上面Teacher的三个实现类,并成功调用了方法。

2.4 ServiceLoader源码解析

public final class ServiceLoader<S> implements Iterable<S>{
    private static final String PREFIX = "META-INF/services/";
    
    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }
    
    public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
    {
        return new ServiceLoader<>(service, loader);
    }
    
    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        // 重点在这里了
        reload();
    }
    
    public void reload() {
        providers.clear();
        // 创建了一个LazyIterator
        lookupIterator = new LazyIterator(service, loader);
    }
    
    // 我们再来看下ServiceLoader.iterator方法,
    public Iterator<S> iterator() {
        return new Iterator<S>() {

            Iterator<Map.Entry<String,S>> knownProviders
                = providers.entrySet().iterator();

            public boolean hasNext() {
                if (knownProviders.hasNext())
                    return true;
                return lookupIterator.hasNext();
            }

            public S next() {
                if (knownProviders.hasNext())
                    return knownProviders.next().getValue();
                // 都交由LazyIterator来实现了
                return lookupIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }

        };
    }
}

经过上面的一系列调用分析,我们知道,ServiceLoader.iterator 的next()调用都交由LazyIterator来实现了

private class LazyIterator implements Iterator<S>{
        Class<S> service;
        ClassLoader loader;
        Enumeration<URL> configs = null;
        Iterator<String> pending = null;
        String nextName = null;

        private LazyIterator(Class<S> service, ClassLoader loader) {
            this.service = service;
            this.loader = loader;
        }
        ...
            
		public S next() {
            if (acc == null) {
            // 直接交由nextService实现
                return nextService();
            } else {
                PrivilegedAction<S> action = new PrivilegedAction<S>() {
                    public S run() { return nextService(); }
                };
                return AccessController.doPrivileged(action, acc);
            }
        }
    
        private S nextService() {
            // 调用hasNextService()实现
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
               ...
            }
            ...
            try {
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                ...
            }
            throw new Error();          // This cannot happen
        }
       
    	private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
                    // 本例中即META-INF/services/xw.demo.DemoService
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        // 加载该路径下的文件,到Enumeration<URL> configs中
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                // 通过解析路径对应文件里的内容
                pending = parse(service, configs.nextElement());
            }
            // nextName即文件内容,本例中即xw.demo.DemoServiceImpl
            nextName = pending.next();
            return true;
        }
    }

代码不算复杂,主要就是解析META-INF/services目录下的以接口全限定名为文件名的文件,解析文件的内容,并创建对应Class的实例

2.5 ServiceLoader的应用

    JDK提供的ServiceLoader技术,有很多广泛的应用。最为大家所熟悉的应该就是DriverManger了。

    DriverManger在加载的时候,就依据ServiceLoader的方式扫描了一下当前有哪些Driver的实现,并主动加载。

public class DriverManager {
 
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    
    private static void loadInitialDrivers() {
        String drivers;
        ...
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
				// 通过ServiceLoader加载
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();

                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
            }
        });
		...
        String[] driversList = drivers.split(":");
        for (String aDriver : driversList) {
            try {
                // 创建对应Driver的实例
                Class.forName(aDriver, true,
                        ClassLoader.getSystemClassLoader());
            } catch (Exception ex) {
            }
        }
    }
}

当我们引入mysql-connection-java.jar包时,会发现

 

也是按照标准方式来实现的自动添加Driver

3.Dubbo的SPI(基础版)

    Dubbo也有自己的SPI,我们先来看其实现,然后再总结其优势。

3.1 提供接口和实现类

package xw.demo.adaptive;
// 较上文中的不同点就是多加了一个@SPI注解
@SPI
public interface Teacher {
    void say();
}

// 三个实现类与上面示例相同,不再赘述

3.2 创建文件

    在META-INF/dubbo目录下创建名为xw.demo.adaptive.Teacher的文件,内容如下

 

注意:也可以将该文件创建在META-INF/services目录下,Dubbo也是支持的,但是为了与JDK原生的使用方式做一定的区分,特地写在META-INF/dubbo目录下

3.3 ExtensionLoader加载测试

ExtensionLoader<Teacher> extensionLoader = ExtensionLoader.getExtensionLoader(Teacher.class);
Teacher teacher = extensionLoader.getExtension("chinese");
teacher.say();
// 结果如下:
chinese

总结:相比较JDK的加载方式而言,Dubbo的这种方式,可以精准的加载对应的实现类,而其他我们不需要的实现类,则不需要被加载。

4.Dubbo的SPI(Wrap版)

    Dubbo在SPI的使用中,有很多包装类的实现。不动声色的就将实现类包装了一层,类似于动态代理的模式。

4.1 提供接口和实现类

    同3.1,就是多一个Wrap的实现类(共四个实现类,另外三个同上,ChineseTeacher、MathTeacher、EnglishTeacher)

package xw.demo.adaptive;
public class TeacherWrapper implements Teacher {
	// 需要有一个Teacher类型的属性
    private Teacher teacher;
    public TeacherWrapper(Teacher teacher) {
        if (teacher == null) {
            throw new IllegalArgumentException("teacher == null");
        }
        this.teacher = teacher;
    }

    @Override
    public void say() {
        System.out.println("start wrap...");
        teacher.say();
    }
}

    并将该实现类添加到上面的xw.demo.adaptive.Teacher文件中,如下

 

4.2 ExtensionLoader加载测试

ExtensionLoader<Teacher> extensionLoader = ExtensionLoader.getExtensionLoader(Teacher.class);
Teacher teacher = extensionLoader.getExtension("chinese");
teacher.say();

// 结果如下:
start wrap...
chinese

与3.3的测试结果有所不同,这里多了TeacherWrapper类的一层封装,所以对ChineseTeacher.say()进行调用时,先打印了封装类的输出语句。

Dubbo有很多关于封装类的使用场景,例如关于Protocol的封装类

 

ProtocolFilterWrapper、ProtocolListenerWrapper,这两个类在对外提供服务时会用到。

5.Dubbo的SPI(Adaptive方式)

    相较于3这种简单的使用方式,Dubbo源码中更常使用的是Adaptive方式,我们先来看下示例。

5.1 提供接口和实现类

package xw.demo.adaptive;
@SPI("chinese")
public interface Teacher {

    void say();

    /**
     * 添加一个方法,入参必须含有URL,必须有@Adaptive注释
     * @param url
     */
    @Adaptive
    void teach(URL url);
}

// 实现类
public class ChineseTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("chinese");
    }

    @Override
    public void teach(URL url) {
        System.out.println("teach chinese");
    }
}

public class MathTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("math");
    }

    @Override
    public void teach(URL url) {
        System.out.println("teach math");
    }
}

public class EnglishTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("english");
    }

    @Override
    public void teach(URL url) {
        System.out.println("teach english");
    }
}

5.2 创建文件

    同3.2,不再赘述

5.3 ExtensionLoader加载测试

5.3.1 测试情况一

Teacher teacher = ExtensionLoader.getExtensionLoader(Teacher.class).getAdaptiveExtension();
URL url = URL.valueOf("test://localhost/test");
teacher.teach(url);

// 结果为
teach chinese

5.3.2 测试情况二

Teacher teacher = ExtensionLoader.getExtensionLoader(Teacher.class).getAdaptiveExtension();
// url有所不同
URL url = URL.valueOf("test://localhost/test?teacher=english");
teacher.teach(url);

// 结果为
teach english

5.3.3 测试情况三

// 给MathTeacher添加@Adaptive注解
@Adaptive
public class MathTeacher implements Teacher {
    @Override
    public void say() {
        System.out.println("math");
    }

    @Override
    public void teach(URL url) {
        System.out.println("teach math");
    }
}

// 测试代码
Teacher teacher = ExtensionLoader.getExtensionLoader(Teacher.class).getAdaptiveExtension();
// 两种url都可以
URL url = URL.valueOf("test://localhost/test?teacher=english");
// URL url = URL.valueOf("test://localhost/test");
teacher.teach(url);

// 结果为
teach math

总结:Adaptive的这种方式在Dubbo中使用较为频繁。通过这三种测试结果我们可以总结出:

1.当在实现类上指定了@Adaptive时,其级别最高,ExtensionLoader.getAdaptiveExtension()默认就返回该实现类

2.当在URL中指定了条件(本例中为teacher=english),则ExtensionLoader.getAdaptiveExtension()会返回条件中指定的实现类

3.当没有任何指定时,则使用默认值,也就是在接口的@SPI注解中指定的(本例为chinese)

注意:总结2中的条件,这个teacher是怎么来的呢?实际就是我们接口的小写之后的字母(slow(Teacher))。

如果接口是多字母组成的会怎么办呢?例如ExtAdaptive,那么不同字母之间就用.来分割,最终变成ext.adaptive

6.Dubbo SPI源码解析

    Dubbo的SPI实现了这么多层次的使用,源码也是比较有意思的,我们一起来看下

6.1 ExtensionLoader.getExtensionLoader()解析

public class ExtensionLoader<T> {
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
    private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
    // 当前关注的类型
    private final Class<?> type;

	public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        ...
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            // 直接创建对应类型的ExtensionLoader
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }
    // 构造方法
    private ExtensionLoader(Class<?> type) {
        // type即为本例中的SpiDemoService
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
}

ExtensionLoader.getExtensionLoader()没有太多花哨的东西,就是设置了ExtensionLoader的基本属性

6.2 ExtensionLoader.getExtension(name)方法分析(先分析简单版本)

public class ExtensionLoader<T> {
	// extensionLoader.getExtension(name) 方法分析
    public T getExtension(String name) {
        ...
        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;
    }
    
    // createExtension()
    private T createExtension(String name) {
        // getExtensionClasses()方法很重要,我们先来分析这个方法
        // getExtensionClasses()返回的已经是 name->实现类的一个map了
        // 所以在这里直接通过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);
            }
            // set方法依赖注入
            // 这里可以通过spring获取bean的方式或SPI的方式注入属性
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            // 这里需要注意下,如果当前接口的实现类有wrap类型的,则获取具体instance时会进行wrap封装
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    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);
        }
    }
    
    // getExtensionClasses
    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;
    }
    
    // loadExtensionClasses()
    private Map<String, Class<?>> loadExtensionClasses() {
        cacheDefaultExtensionName();

        Map<String, Class<?>> extensionClasses = new HashMap<>();

        // 这里有三种搜索加载策略,关键点
        // DubboInternalLoadingStrategy:加载META-INF/dubbo/internal/目录下的文件
        // DubboLoadingStrategy:加载META-INF/dubbo/目录下的文件
        // ServicesLoadingStrategy:加载META-INF/services/目录下的文件
        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;
    }
    
    // loadDirectory
    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();

            ...
            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();
                    // 搜索到的文件,加载文件内容
                    // 并且将name对应的Class信息,包装到cachedNames这个map中,供后面查询使用
                    loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
                }
            }
        } catch (Throwable t) {
            ...
        }
    }
    
    // loadResource()
    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;
                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和对应的类全限定名
                                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) {
           ...
        }
    }
    
    // loadClass
    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);
            // 什么样的才是wrapperClass,把当前接口当做构造函数的入参就叫包装类
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            // 最终获取对应的class信息(本例中就是在这里获取)
            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);
                }
            }
        }
    }
}

总体还是稍微有点绕的,简单来说,就是在寻找Interface对应name的实现类时,通过扫描ClassPath下指定的三个目录META-INF/dubbo/internal/、META-INF/dubbo/、META-INF/services/,找到对应Interface名的文件,然后加载文件内容,这时比对name,将符合的name的value值实例化为对象。

6.3 ExtensionLoader.getAdaptiveExtension(name)方法分析(Adaptive)

public class ExtensionLoader<T> {
	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);
                    }
                }
            }
        }

        return (T) instance;
    }
    
    // createAdaptiveExtension()
    private T createAdaptiveExtension() {
        try {
            // getAdaptiveExtensionClass()主要点
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }
    
    // getAdaptiveExtensionClass()
    private Class<?> getAdaptiveExtensionClass() {
        // 这里与5.2中的过程一样的,中间的过程不再赘述,最终还是到达loadClass()方法,我们直接分析与上面不同的分支
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
    
    // loadClass()
    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                           boolean overridden) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            ...
        }
        // 见4.3.3 测试情况三,当类上有@Adaptive注解时,直接将当前该类赋值给 ExtensionLoader.cachedAdaptiveClass属性
        // 后续返回getAdaptiveExtensionClass()方法时,会看到,cachedAdaptiveClass不为空,则会直接将当前类返回回去。所以带有@Adaptive注解的实现类优先级最高
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz, overridden);
            // 什么样的才是wrapperClass,把当前接口当做构造函数的入参就叫包装类
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
            // 最终获取对应的class信息(本例中就是在这里获取)
            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);
                }
            }
        }
    }
}

那么问题来了,针对4.3.1 4.3.2的这两种测试情况怎么看这个代码呢?我们回到getAdaptiveExtensionClass()方法

public class ExtensionLoader<T> {
	private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        // 非4.3.3情况,则cachedAdaptiveClass会为空
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        // 逻辑走到这
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
    
    private Class<?> createAdaptiveExtensionClass() {
        // 通过javassist的方式动态生成其代理类,具体我们不再深入,我们来看下生成的代理类的具体代码
        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);
    }
}

通过javassist的方式生成的动态代理类代码(针对本例而言)

public class Teacher$Adaptive implements xw.demo.adaptive.Teacher {
    public void teach(org.apache.dubbo.common.URL arg0) {
        if (arg0 == null) {
            throw new IllegalArgumentException("url == null");
        }
        org.apache.dubbo.common.URL url = arg0;
        // 供调用方手动设置参数,参数名为teacher,具体使用方式参见4.3.2 测试情况二
        // 默认值为chinese,是由Teacher接口@SPI("chinese")指定的
        String extName = url.getParameter("teacher", "chinese");
        if (extName == null) {
            throw new IllegalStateException("Failed to get extension (xw.demo.adaptive.Teacher) name from url (" + url.toString() + ") use keys([teacher])");
        }
        // 最终回归到原生的调用方式getExtension(name),类似于3.3的方式
        xw.demo.adaptive.Teacher extension = (xw.demo.adaptive.Teacher) ExtensionLoader.getExtensionLoader(xw.demo.adaptive.Teacher.class).getExtension(extName);
        extension.teach(arg0);
    }

    public void say() {
        throw new UnsupportedOperationException("The method public abstract void xw.demo.adaptive.Teacher.say() of interface xw.demo.adaptive.Teacher is not adaptive method!");
    }
}

总结:

我们再把上面的获取代理类的顺序重复一下:

1.当在实现类上指定了@Adaptive时,其级别最高,ExtensionLoader.getAdaptiveExtension()默认就返回该实现类

2.当在URL中指定了条件,则ExtensionLoader.getAdaptiveExtension()会返回条件中指定的实现类

3.当没有任何指定时,则使用默认值,也就是在接口的@SPI注解中指定的

Guess you like

Origin blog.csdn.net/qq_26323323/article/details/121419762