dubbo源码解析(一): 扩展点加载(ExtensionLoader)

3 篇文章 0 订阅

阿里开源的RPC框架dubbo是一个庞大而复杂的系统,对源码的分析也没法做到一应俱全。这里从几个dubbo的关键点进行系统的分析,本文先带着大家一起来看看dubbo的扩展点加载机制。

dubbo的扩展点加载从jdk标准的SPI(Service Provider Interface)扩展点发现机制加强而来。在分析dubbo的ExtensionLoader之前,我们先来分析一下jdk标准的SPI机制

以下文字摘自于stackoverflow的一个回答:
http://stackoverflow.com/questions/2954372/difference-between-spi-and-api

The API is the description of classes/interfaces/methods/… that you call and use to achieve a goal and
The SPI is the description of classes/interfaces/methods/… that you extend and implement to achieve a goal
Put differently, the API tells you what a specific class/method does for you and the SPI tells you what you must do to conform.
Usually API and SPI are separate. For example in JDBC the Driver class is part of the SPI: If you simply want to use JDBC, you don’t need to use it directly, but everyone who implements a JDBC driver must implement that class.

这里主要阐述了API和SPI的区别。说到SPI,一个最经典的例子便是java的数据库驱动jdbc,其实jdk自带的jdbc驱动并没有实现对数据库的操作,而是开放了一系列的接口供各大数据库厂商和开源社区进行扩展,在使用时加载具体的数据库驱动来实现对数据库的操作。我们先看一个SPI的例子。

public interface IOperation {
    public int operation(int a, int b);
}
public class PlusOperationImpl implements IOperation {
    public int operation(int a, int b) {
        return a + b;
    }
}
public class MultiplyOperationImpl implements IOperation {
    public int operation(int a, int b) {
        return a * b;
    }
}

这里做了一个数学操作的接口,写了两个实现类,加法和乘法。
为了让SPI能找到这两个扩展点(PlusOperationImpl和MultiplyOperationImpl),需要一个配置文件,文件名为接口名com.jd.roger.spidemo.api.IOperation,文件内容为该接口的实现类,并将该文件放到META-INF/services目录下。

com.jd.roger.spidemo.impl.MultiplyOperationImpl
com.jd.roger.spidemo.impl.PlusOperationImpl

下面我们来测试一下:

public class Main {
    public static void main(String[] args) {
        ServiceLoader<IOperation> operations = ServiceLoader.load(IOperation.class);
        Iterator<IOperation> operationIterator = operations.iterator();
        while (operationIterator.hasNext()) {
            IOperation operation = operationIterator.next();
            System.out.println(operation.getClass().toString());
            System.out.println(operation.operation(1, 2));
        }
    }
}

输出的日志为:

class com.jd.roger.spidemo.impl.MultiplyOperationImpl
2
class com.jd.roger.spidemo.impl.PlusOperationImpl
3

以上就是一个简单的jdk spi的例子。可以看到spi的作用是规范一种服务的接口,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件,该文件的内容为接口的具体实现类。当使用方装载该接口时,spi会自动将该接口的实现实例化后注入到代码中。这样做的好处是在对接口进行扩展的时候,只需增加新的接口实现和修改配置文件,对原有的代码不造成影响。

在了解了spi的基本功能后,下面来分析一下dubbo的ExtensionLoader,以下文字摘自dubbo官网:

Dubbo改进了JDK标准的SPI的以下问题:

  • JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK标准的ScriptEngine,通过getName();获取脚本类型的名称,但如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致RubyScriptEngine类加载失败,这个失败原因被吃掉了,和ruby对应不起来,当用户执行ruby脚本时,会报不支持ruby,而不是真正失败的原因。
  • 增加了对扩展点IoC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。

我们先把这段话放在这里,等到分析完ExtensionLoader后再回过头来看看这三句话的具体意思。

对于dubbo这么一个庞大的系统而言,对于扩展的支持是十分必要的,同时作为一款开源软件,避免不了的会有多个贡献者去完善dubbo的功能,扩展点的引入极大地方便了代码的扩展。
在分析ExtensionLoader之前,先大概介绍一下dubbo代码的构成(源自dubbo官网):

  • config,配置层,对外配置接口,以ServiceConfig, ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类
  • proxy,服务代理层,服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory
  • registry,注册中心层,封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory, Registry, RegistryService
  • cluster,路由层,封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster, Directory, Router, LoadBalance
  • monitor,监控层,RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory, Monitor, MonitorService
  • protocol,远程调用层,封将RPC调用,以Invocation, Result为中心,扩展接口为Protocol, Invoker, Exporter
  • exchange,信息交换层,封装请求响应模式,同步转异步,以Request, Response为中心,扩展接口为Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • transport,网络传输层,抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel, Transporter, Client, Server, Codec
  • serialize,数据序列化层,可复用的一些工具,扩展接口为Serialization, ObjectInput, ObjectOutput, ThreadPool

对于上述的每一层而言,dubbo均提供了不止一种的扩展方式,例如注册中心registry就分为:DubboRegistry,MulticastRegistry,ZookeeperRegistry和RedisRegistry,又如远程调用protocol分为:DubboProtocol,MockProtocol,InjvmProtocol,RmiProtocol,HessianProtocol,HttpProtocol,WebServiceProtocol,ThriftProtocol和RedisProtocol。整个dubbo系统就好像一个布满插槽的面板,由用户针对每个功能选择不同的插件插入插槽中,最后组装成整个dubbo系统。

dubbo的扩展点加载机制主要的实现类便是ExtensionLoader,从功能上来看,扩展点分为加载和获取两个部分,这里涉及到了各个扩展点的注入和实例化,以及对所有扩展点的管理,dubbo把扩展点分为了三类:
可自动激活的扩展点(Activate)
自适应的扩展点(Adaptive)
普通的扩展点

其实Activate的扩展点和Adaptive的扩展点就是对普通的扩展点进行了一次包装。dubbo提供了三个函数去获得这三种扩展点,分别是:
getAdaptiveExtension
getActivateExtension
getExtension

下面我们以dubbo启动时加载protocol

ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()

来具体分析一下ExtensionLoader这个类。
ExtensionLoader具有一个私有的构造函数和静态的getExtensionLoader方法

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 interface!");
    }
    if(!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type(" + type + 
                ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    }

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

先对传入的type进行合法性校验,包括是否为空,是否为一个接口,以及该接口是否带有SPI的注解,注意这里的SPI注解和jdk的SPI没有任何关系,只是dubbo自己的注解,为了标识该接口是一个扩展点。

package com.alibaba.dubbo.common.extension;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
    String value() default "";
}

在进行完合法性校验后,会从EXTENSION_LOADERS缓存寻找对应的loader,没有则创建一个新的。跳到ExtensionLoader的构造函数。

private ExtensionLoader(Class<?> type) {
    this.type = type;
    //新建一个ExtensionFactory, 如果本身该load就是ExtensionFactory类型, 则objectFactory置为null
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

除了记录该ExtensionLoader实例对应的type之外,还会创建一个ExtensionFactory的ExtensionLoader,并通过ExtensionLoader获取自适应的扩展点(getAdaptiveExtension),将获取到的实例赋值给objectFactory。在创建ExtensionFactory的loader的时候,会将其自身的objectFactory置位null。关于ExtensionFactory,在本文的后面会进行详细的分析。

下面进入getAdaptiveExtension函数,去获取一个自适应的扩展点。

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("fail to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }
        else {
            throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
        }
    }

    return (T) instance;
}

当缓存(cachedAdaptiveInstance)中没有的时候,调用createAdaptiveExtension创建自适应扩展点,这里因为是单例模式,因此对instance进行了两次的null判定。

private T createAdaptiveExtension() {
    try {
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
    }
}

先是调用getAdaptiveExtensionClass获得自适应扩展点的class对象,再进行注入操作。我们先来看看getAdaptiveExtensionClass函数

private Class<?> getAdaptiveExtensionClass() {
    getExtensionClasses();
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    //如果在调用后,cachedAdaptiveClass没有被赋值,则自动生成一个自适应的扩展点
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}

到这里我们终于快接触到了ExtensionLoader的核心部分——getExtensionClasses()函数,该函数的作用就是扫描classpath底下的配置文件,加载该interface对应的所有的扩展点,并将扩展点进行分类(Adaptive,Activate),以及生成包装类等。在扫描的过程中,如果发现该扩展类为Adaptive类型,则将该class缓存到cachedAdaptiveClass中。如果所有的扩展类均不是Adaptive类型,则调用createAdaptiveExtensionClass生成一个Adaptive类型的扩展类。

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

如果cachedClasses缓存中没有,则调用loadExtensionClasses去加载

private Map<String, Class<?>> loadExtensionClasses() {
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    if(defaultAnnotation != null) {
        //这里根据注解的值,缓存default的扩展点
        String value = defaultAnnotation.value();
        if(value != null && (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<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    //调用loadFile函数根据不同的路径去加载扩展点
    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadFile(extensionClasses, DUBBO_DIRECTORY);
    loadFile(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

loadFile函数会去DUBBO_INTERNAL_DIRECTORY、DUBBO_DIRECTORY和SERVICES_DIRECTORY这三个路径下去寻找配置文件,类似于jdk的SPI中放在META-INF/services目录下的文件,这里给出protocol的配置文件com.alibaba.dubbo.rpc.Protocol

registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached=memcom.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

可以看到protocol的扩展类型还是很多的,下面我们进入loadFile函数

private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
    String fileName = dir + type.getName();
    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()) {
                java.net.URL url = urls.nextElement();
                try {
                    BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                    try {
                        String line = null;
                        while ((line = reader.readLine()) != null) {
                            //去除注释
                            final int ci = line.indexOf('#');
                            if (ci >= 0) line = line.substring(0, ci);
                            line = line.trim();
                            if (line.length() > 0) {
                                try {
                                    String name = null;
                                    int i = line.indexOf('=');
                                    if (i > 0) {
                                        name = line.substring(0, i).trim();
                                        line = line.substring(i + 1).trim();
                                    }
                                    if (line.length() > 0) {
                                        Class<?> clazz = Class.forName(line, true, classLoader);
                                        //判断clazz是否为type的子类,如果不是,抛异常
                                        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种类的扩展类
                                        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());
                                            }
                                        } else {
                                            try {
                                                //检查是否有拷贝构造函数
                                                clazz.getConstructor(type);
                                                Set<Class<?>> wrappers = cachedWrapperClasses;
                                                if (wrappers == null) {
                                                    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                                                    wrappers = cachedWrapperClasses;
                                                }
                                                wrappers.add(clazz);
                                            } catch (NoSuchMethodException e) {
                                                clazz.getConstructor();
                                                if (name == null || name.length() == 0) {
                                                    name = findAnnotationName(clazz);
                                                    if (name == null || name.length() == 0) {
                                                        if (clazz.getSimpleName().length() > type.getSimpleName().length()
                                                                && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                                                            name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                                                        } else {
                                                            throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                                                        }
                                                    }
                                                }
                                                String[] names = NAME_SEPARATOR.split(name);
                                                if (names != null && names.length > 0) {
                                                    //注解为Activate种类的class
                                                    Activate activate = clazz.getAnnotation(Activate.class);
                                                    if (activate != null) {
                                                        cachedActivates.put(names[0], activate);
                                                    }
                                                    for (String n : names) {
                                                        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());
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                } catch (Throwable t) {
                                    IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
                                    exceptions.put(line, e);
                                }
                            }
                        } // end of while read lines
                    } finally {
                        reader.close();
                    }
                } catch (Throwable t) {
                    logger.error("Exception when load extension class(interface: " +
                                        type + ", class file: " + url + ") in " + url, t);
                }
            } // end of while urls
        }
    } catch (Throwable t) {
        logger.error("Exception when load extension class(interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}

这个函数非常长,而且各种if else的缩进也很深,大概的处理流程是对配置文件中的各个扩展点进行如下操作
1. 判断该扩展点是否是要加载的interface的子类,如果不是则忽略
2. 如果该class带有Adaptive的注解,则缓存到cachedAdaptiveClass中
3. 如果该class具有拷贝构造函数,则缓存到cachedWrapperClasses中
4. 如果该class带有Activate注解,则缓存到cachedActivates中
5. 将所有的扩展点缓存到cachedClasses中

到这里,一个type对应的所有扩展点均已加载完毕,我们再回到getAdaptiveExtensionClass中,看一下如果没有自适应的扩展点,调用createAdaptiveExtensionClass是如何生成一个自适应的类的。

private Class<?> createAdaptiveExtensionClass() {
    String code = createAdaptiveExtensionClassCode();
    ClassLoader classLoader = findClassLoader();
    com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
    return compiler.compile(code, classLoader);
}

先调用createAdaptiveExtensionClassCode函数生成一段文本代码,然后再获取Compiler类型的扩展点去编译这段代码。Compiler的扩展点加载也是通过ExtensionLoader.getExtensionLoader进行的,不再赘述。这里用到的具体类是javassist,将文本代码生成一个具体的class。还是以Protocol为例,生成的文本代码如下:

package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
    }

    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
        if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();

        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");

        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);

        return extension.export(arg0);
    }

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg1;
        String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
        if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");

        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);

        return extension.refer(arg0, arg1);
    }
}

可以看到这里默认的rpc方案就是dubbo自身的方案

url.getProtocol() == null ? "dubbo" : url.getProtocol()

到这里所有的扩展点均已生成完毕,我们回到createAdaptiveExtension函数,看一下injectExtension

private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            for (Method method : instance.getClass().getMethods()) {
                //寻找set方法
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                        //从objectFactory获取要注入的扩展点
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            //注入到具体的类中
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        logger.error("fail to inject via method " + method.getName()
                                + " of interface " + type.getName() + ": " + e.getMessage(), e);
                    }
                }
            }
        }
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    return instance;
}

该方法不仅仅用在自适应扩展点的注入,也适用于其他类型的扩展点,我们来看一下注入的大致流程
1. 遍历该instance的所有方法,找到以set开头的方法,准备进行注入。
2. 调用objectFactory.getExtension()方式获取要注入的实例。
3. 调用method.invoke进行注入。

这里,我们又看到了前面出现的ExtensionFactory,前文提到每个扩展点的ExtensionLoader实例中均有一个objectFactory来存储ExtensionFactory实例,并且这个objectFactory也是通过getExtensionLoader方式产生的ExtensionFactory自适应的扩展点

objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());

ExtensionFactory扩展点分为SpiExtensionFactory、AdaptiveExtensionFactory和SpringExtensionFactory三种,下面我们来分析一下AdaptiveExtensionFactory的代码,看看调用objectFactory.getExtension的时候都发生了什么。

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        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);
    }

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

在AdaptiveExtensionFactory的构造函数中,将SpiExtensionFactory和SpringExtensionFactory实例化后存入factories中。
在getExtension中,会依次调用SpiExtensionFactory和SpringExtensionFactory的方法来寻找扩展点,找到即返回。以SpiExtensionFactory为例来看一下具体的getExtension函数:

public <T> T getExtension(Class<T> type, String name) {
    if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
        ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
        if (loader.getSupportedExtensions().size() > 0) {
            return loader.getAdaptiveExtension();
        }
    }
    return null;
}

其实就是对相应的type生成对应的ExtensionLoader再找到Adaptive扩展点返回。至此,便完成了一个class实例化后,其内部所有的可注入的变量的注入操作。ExtensionFactory就相当于所有扩展点的工厂,提供相应的接口去取获取扩展点。

对于扩展点的注入,这里引用一段dubbo官网的例子来辅助理解一下这个机制

扩展点自动装配
加载扩展点时,自动注入依赖的扩展点
加载扩展点时,扩展点实现类的成员如果为其它扩展点类型,ExtensionLoader在会自动注入依赖的扩展点。

ExtensionLoader通过扫描扩展点实现类的所有set方法来判定其成员。

即ExtensionLoader会执行扩展点的拼装操作。

示例:有两个为扩展点CarMaker(造车者)、wheelMaker(造轮者)

接口类如下:

public interface CarMaker {
    Car makeCar();
}

public interface WheelMaker {
    Wheel makeWheel();
}

CarMaker的一个实现类:

public class RaceCarMaker implemenets CarMaker {
    WheelMaker wheelMaker;

    public setWheelMaker(WheelMaker wheelMaker) {
        this.wheelMaker = wheelMaker;
    }

    public Car makeCar() {
        // ...
        Wheel wheel = wheelMaker.makeWheel();
        // ...
        return new RaceCar(wheel, ...);
    }
}

ExtensionLoader加载CarMaker的扩展点实现RaceCar时,setWheelMaker方法的WheelMaker也是扩展点则会注入WheelMaker的实现。

关于扩展点自动包装(Wrapper),扩展点自动装配、扩展点自适应(Adaptive)和扩展点自动激活(Activate)的概念,大家可以自行参阅一下dubbo的官网,之后再来看源码分析,这样理解得会更加清楚。

最后,我们再来看一下ExtensionLoader的getExtension()方法,看看如何获取一个指定的扩展点

public T getExtension(String name) {
    if (name == null || name.length() == 0)
        throw new IllegalArgumentException("Extension name == null");
    if ("true".equals(name)) {
        return getDefaultExtension();
    }
    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) {
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}

先从cachedInstances中寻找,如果没有找到的话,调用createExtension()方法进行生成, createExtension就是调用了前文中提到的getExtensionClasses()方法。

至此dubbo中关于ExtensionLoader的扩展点加载机制已经分析完了,后续我们将继续分析dubbo服务的启动,那里面大家将看到dubbo是如果使用这些已经加载好的扩展点的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值