Dubbo源码分析----ExtensionLoader模块

       Dubbo的扩展采用Dubbo SPI机制实现,SPI机制(Service Provider Interface)是指一些提供给你继承、扩展,完成自定义功能的类、接口或者方法。SPI把控制权交个调用方,调用方来决定使用该使用哪个实现。

       Dubbo扩展机制的核心类是ExtensionLoader,该类通过静态方法getExtensionLoader获取一个指定接口的ExtensionLoader实例。

ExtensionLoader源码分析 Start

①找源码分析入口

// 我们以这个作为Dubbo SPI源码分析的入口
Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

// 为什么使用getAdaptiveExtension()来作为源码入口,而不用getExtension(String name)呢?
// 因为我们在调用服务和发布服务的时候,我们需要用到协议。我们在服务发布的时候,在源码包dubbo-config/dubbo-config-api
// 包下的ServiceConfig类中有一个默认的机制(如下图所示)
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
// 所以我们使用这个默认的机制来作为入口。了解getAdaptiveExtension()后,再了解指定的Extension就更简单了(getExtension)


 ②找到了入口,我们来分析ExtensionLoader类  (ExtensionLoader类位于dubbo-common包下,如下图所示)

    

        在dubbo-common包中,我们能够看到Dubbo提供了@Activate、@Adaptive(适配器)、@DisableInject、@SPI(扩展点)几个注解;在factory文件夹下,提供了三种Extension工厂类,分别是:AdaptiveExtensionFactory、SpiExtensionFactory,另一个工厂类为SpringExtensionFactory(在dubbo-config/dubbo-config-spring/extension包下) 。如上图所示。

结构图如下:


 ③调用Dubbo协议,我们先来看看Dubbo框架官方定义的Protocol接口(注释为作者手动添加)

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.Adaptive;
import com.alibaba.dubbo.common.extension.SPI;

/**
 * Protocol. (API/SPI, Singleton, ThreadSafe)
 */
@SPI("dubbo")
public interface Protocol {
    
    /**
     * 获取缺省端口,当用户没有配置端口时使用。
     * 
     * @return 缺省端口
     */
    int getDefaultPort();

    /**
     * 暴露远程服务:<br>
     * 1. 协议在接收请求时,应记录请求来源方地址信息:RpcContext.getContext().setRemoteAddress();<br>
     * 2. export()必须是幂等的,也就是暴露同一个URL的Invoker两次,和暴露一次没有区别。<br>
     * 3. export()传入的Invoker由框架实现并传入,协议不需要关心。<br>
     * 
     * @param <T> 服务的类型
     * @param invoker 服务的执行体
     * @return exporter 暴露服务的引用,用于取消暴露
     * @throws RpcException 当暴露服务出错时抛出,比如端口已占用
     */
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    /**
     * 引用远程服务:<br>
     * 1. 当用户调用refer()所返回的Invoker对象的invoke()方法时,协议需相应执行同URL远端export()传入的Invoker对象的invoke()方法。<br>
     * 2. refer()返回的Invoker由协议实现,协议通常需要在此Invoker中发送远程请求。<br>
     * 3. 当url中有设置check=false时,连接失败不能抛出异常,并内部自动恢复。<br>
     * 
     * @param <T> 服务的类型
     * @param type 服务的类型
     * @param url 远程服务的URL地址
     * @return invoker 服务的本地代理
     * @throws RpcException 当连接服务提供方失败时抛出
     */
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;

    /**
     * 释放协议:<br>
     * 1. 取消该协议所有已经暴露和引用的服务。<br>
     * 2. 释放协议所占用的所有资源,比如连接和端口。<br>
     * 3. 协议在释放后,依然能暴露和引用新的服务。<br>
     */
    void destroy();

}

       在该接口中,我们看到该接口有使用到一个@SPI("dubbo")注解,说明当前的这个类是一个【扩展点】,这个扩展点默认
是dubbo。这个默认扩展点的实现,约定的文件路径、文件名、文件内容,又在哪里能找到呢?

       我们可以在dubbo-rpc/dubbo-rpc-dubbo中的resources文件夹中可以找到Dubbo SPI机制规定的文件名,然后进入该文件名,便可以看到默认dubbo协议的具体实现类:dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol。如下图所示:

       进入dubbo协议具体实现类

/**
 * dubbo protocol support.
 */
public class DubboProtocol extends AbstractProtocol {

    public static final String NAME = "dubbo";

    public static final int DEFAULT_PORT = 20880;

    private static final String IS_CALLBACK_SERVICE_INVOKE = "_isCallBackServiceInvoke";
    private static DubboProtocol INSTANCE;
    private final Map<String, ExchangeServer> serverMap = new ConcurrentHashMap<String, ExchangeServer>(); // <host:port,Exchanger>

    //......省略部分代码

    @Override
    public int getDefaultPort() {
        return DEFAULT_PORT;
    }
}

      通过int port = ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension().getDefaultPort();拿到的默认端口,现在你应该就明白为什么返回的是20880了吧。


④现在可以开始正式源码分析了,我们来分析geExtensionLoader(Class<T> type)方法(请按代码中序号查看源码!!!)

//1.根据一个类型获取一个扩展的ExtensionLoader
@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 interface!");
    }
    if (!withExtensionAnnotation(type)) {
        throw new IllegalArgumentException("Extension type(" + type +
                ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
    }

    //2.根据类型,从缓存中取得一个ExtensionLoader(EXTENSION_LOADERS为ConcurrentMap类型的缓存)
    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    //如果缓存中没有
    if (loader == null) {
        //3.则通过new的形式,新建一个ExtensionLoader(初始化)
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

 ⑤我们来分析如何初始化一个ExtensionLoader类

private ExtensionLoader(Class<?> type) {
    //4.这里这个tpye赋值,着重留心一下
    this.type = type;
    //5.调用getAdaptiveExtension()方法(非常关键),来实现一个自适应扩展点,获得一个自适应扩展点
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

 ⑥我们来分析一下序号5中的getAdaptiveExtension()方法

//获取适配器扩展点
@SuppressWarnings("unchecked")
public T getAdaptiveExtension() {
    //6.cachedAdaptiveInstance实例为一个Holder类型的缓存,通过get能获得一个实例对象
    Object instance = cachedAdaptiveInstance.get();
    //初次进入,实例为空
    if (instance == null) {
        // 双重检查锁
        if (createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        //7.创建一个AdaptiveExtension实例
                        instance = createAdaptiveExtension();
                        //8.设置到cachedAdaptiveInstance缓存中
                        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;
}

 ⑦ 我们来分析一下创建AdaptiveExtension实例的过程(序号7中的createAdaptiveExtension()方法)

@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
    try {
        //9.injectExtension方法,传递一个参数,拿到一个适配器的扩展点的实例,本例重点分析getAdaptiveExtensionClass()方法
        //injectExtension()方法分析(先了解清除getAdaptiveExtensionClass()方法后再来了解)
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
    }
} 

   injectExtension( )方法分析,建议在看完所有步骤之后再来看,injectExtension( )方法, 请直接跳转至 ⑰ 步查看


⑧继续分析序号9中getAdaptiveExtensionClass()方法,如何获得一个适配器扩展点的class类

private Class<?> getAdaptiveExtensionClass() {
    //10.获得扩展点的实现类
    getExtensionClasses();
    //11.这里也重点关注一下(如果序号10中,步骤14中,cachedAdaptiveClass有赋值,说明有匹配到适配器,否则通过序号12,使用动态代理来通过URL来判断具体使用哪种协议)
    if (cachedAdaptiveClass != null) {
        return cachedAdaptiveClass;
    }
    //12.基于动态代理,创建一个适配器的扩展点
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}		

⑨继续分析序号12中的createAdaptiveExtensionClass()方法,如何创建适配器扩展点类

//创建一个适配器扩展点(基于动态代理,创建一个动态的字节码文件)
private Class<?> createAdaptiveExtensionClass() {
    //13.生成的字节码文件(基于URL来判断,应该基于哪个服务进行发布)
    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);
}

       附:序号13动态代理生成的代码(因为有接口类,此处使用的是JDK动态代理),如需了解JDK动态代理等内容,请移步本文开头,点击链接前去了解。

package com.alibaba.dubbo.rpc;

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

//动态代理,生成的自适应适配器扩展点
//针对refer和export两个方法,做了一个动态代理来实现
//此处的自适应是什么意思:即我们在运行的时候,根据当前的一个状态,去得到一个符合当前场景的协议
public class Protocol$Adaptive 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.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        //获取到URL
        com.alibaba.dubbo.common.URL url = arg1;
        //通过URL判断,当前需要使用什么协议发布
        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);
    }

    //发布服务
    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
        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])");
        //ExtensionLoader就是一个非常牛B的设计
        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);
    }
}

        至此,Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();该方法得到的具体是一个什么对象,我们便能够知道了。它得到的是一个代理类对象Protocol$Adaptive。当前该服务具体需要使用什么协议,我们可以通过URL来判断


自适应适配器扩展点,通过JDK动态代理已经生成。根据Dubbo SPI机制,我们在META-INF/dubbo路径下配置的内容什么时候被加载呢?我们可以回到序号10来看getExtensionClasses()方法的实现

//加载扩展点的实现类(META-INF/dubbo,META-INF/dubbo/internal,META-INF/services三个文件夹中文件)
private Map<String, Class<?>> getExtensionClasses() {
    //缓存中获得map.大致结构类似com.alibaba.dubbo.rpc.Protocol => [com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol,MemcacheProtocol...]
    Map<String, Class<?>> classes = cachedClasses.get();
    //双重检查锁 double-check
    if (classes == null) {
        synchronized (cachedClasses) {
            classes = cachedClasses.get();
            if (classes == null) {
                //14.加载扩展点的实现类
                classes = loadExtensionClasses();
                //15.将扩展点实现类放入缓存
                cachedClasses.set(classes);
            }
        }
    }
    return classes;
}

⑪分析序号14,加载扩展点实现类方法loadExtensionClasses()方法的实现 

// 此方法在上一步getExtensionClasses()方法中已经使用synchronized锁包围
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
    //此处这个type:翻回序号4、5再瞅瞅,在 new ExtensionLoader()的时候通过 this.type = type 赋值的,你就知道了。ExtensionLoader.getExtensionLoader(Protocol.class),就是这个Protocol.class
    //通过getAnnotation()判断当前Protocol是否是扩展点,返回SPI注解(回想一下Dubbo提供的Protocol,是被一个@SPI("dubbo")所注解的)
    final SPI defaultAnnotation = type.getAnnotation(SPI.class);
    //如果SPI注解内容不为空
    if (defaultAnnotation != null) {
        String value = defaultAnnotation.value();
        //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));
            }
            //赋值(此处如果是默认dubbo协议,name这个cachedDefaultName中就是dubbo)
            if (names.length == 1) cachedDefaultName = names[0];
        }
    }

    Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
    //16.loadDirectory,加载三个不同路径下对应的文件,然后赋值给extensionClasses
    loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
    loadDirectory(extensionClasses, DUBBO_DIRECTORY);
    loadDirectory(extensionClasses, SERVICES_DIRECTORY);
    return extensionClasses;
}

      第16步中,loadDirectory()方法,如果想继续研究,可以继续下面⑫⑬⑭步骤,如果看不懂⑫⑬⑭步,那么你只需要知道:

      ①初次进入,loadDirectory()方法返回结果,如下图:

      ②获取具体扩展类实现是,loadDirectory()方法会将所有的协议实现都放入缓存cacheClasses中,结果如下图,你也可以直接跳到⑮步查看


⑫分析序号16中的loadDirectory()方法(根据序号15,便能够理解Dubbo SPI规定的文件存放路径了吧,共3种路径)

private void loadDirectory(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 resourceURL = urls.nextElement();
                //17.加载文件
                loadResource(extensionClasses, classLoader, resourceURL);
            }
        }
    } catch (Throwable t) {
    logger.error("Exception when load extension class(interface: " +
                type + ", description file: " + fileName + ").", t);
    }
}

⑬分析序号17中loadResource()方法,继续加载配置资源

private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
    try {
        //读取到文件内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
        try {
            String line;
            //读取文件每一行
            while ((line = reader.readLine()) != null) {
                final int ci = line.indexOf('#');
                if (ci >= 0) line = line.substring(0, ci);
                line = line.trim();
                if (line.length() > 0) {
                    try {
                        String name = null;
                        int i = line.indexOf('=');
                        if (i > 0) {
                            //获取到key
                            name = line.substring(0, i).trim();
                            //获取到对应的实现类
                            line = line.substring(i + 1).trim();
                        }
                        if (line.length() > 0) {
                            //18.通过Class.forName()加载类
                            loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
                        }
                    } catch (Throwable t) {
                        IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
                        exceptions.put(line, e);
                    }
                }
            }
        } finally {
            reader.close();
        }
    } catch (Throwable t) {
        logger.error("Exception when load extension class(interface: " +
                type + ", class file: " + resourceURL + ") in " + resourceURL, t);
    }
}

⑭分析序号18中loadClass()方法,使用Class.forName()来加载类

private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
    //加载对应的实现类,并且判断该实现类是否实现了Protocol接口(即:必须是当前的加载的扩展点的实现)
    if (!type.isAssignableFrom(clazz)) {
        throw new IllegalStateException("Error when load extension class(interface: " +
                type + ", class line: " + clazz.getName() + "), class "
                + clazz.getName() + "is not subtype of interface.");
    }
    //判断是否有自定义适配类(涉及到Adaptive),如果有,则在前面讲过的获取适配类的时候,直接返回当前的自定义适配类,不需要再动态创建
    //Adaptive(此处你会不会想到步骤②中的@Adaptive注解)
    //1.@Adaptive如果是配置在类级别上,表示自定义适配器
    //2.@Adaptive如果是配置在方法级别上,表示需要动态生成适配器类

    //判断类级别,是否有@Adaptive注解(适配器扩展点)
    if (clazz.isAnnotationPresent(Adaptive.class)) {
        if (cachedAdaptiveClass == null) {
            //赋值
            cachedAdaptiveClass = clazz;
        } else if (!cachedAdaptiveClass.equals(clazz)) {
            throw new IllegalStateException("More than 1 adaptive class found: "
                    + cachedAdaptiveClass.getClass().getName()
                    + ", " + clazz.getClass().getName());
        }
    } else if (isWrapperClass(clazz)) {//isWrapperClass()方法
        //得到带有一个public DubboProtocol(Protocol protocol)的扩展点,进行包装wrapper(为什么要包装,参见(Dubbo源码分析二))
        Set<Class<?>> wrappers = cachedWrapperClasses;

        if (wrappers == null) {
            cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
            wrappers = cachedWrapperClasses;
        }
        wrappers.add(clazz);//包装类 ProtocolFilterWrapper(ProtocolListenerWrapper(Protocol))
    } else {
        clazz.getConstructor();
        if (name == null || name.length() == 0) {
            name = findAnnotationName(clazz);
            if (name.length() == 0) {
                throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
            }
        }
        String[] names = NAME_SEPARATOR.split(name);
        if (names != null && names.length > 0) {
            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());
                }
            }
        }
    }
}

⑮在⑪步中的 loadExtensionClasses 方法,我们可以看到已经将所有扩展点的实现都 缓存到了名称为 extensionClasses 的 Map中, 在第 ⑩ 步中,然后将 extensionClasses 的结果 set 到 类型为 Holder<Map<String,Class<?>>> 的 cachedClasses 缓存中。

      依次回退至第④步,此时最终getExtensionLoader(Class<T> type) 方法,根据传参type类型,返回的结果也不同,动态创建一个适配器,即适配器模式。本例传参为 Protocol,返回结果:com.alibaba.dubbo.common.extension.ExtensionLoader[com.alibaba.dubbo.rpc.Protocol]

       当获取到ExtensionLoader类之后,Dubbo默认的协议为 dubbo协议,Dubbo 会通过 getExtension(String name)方法,以参数的形式直接获取 dubbo 协议SPI的实现类 。经过多层方法调用,会再次载入到 ⑪ 步中的 loadDirectory()方法。getExtension()获取具体实现类的方法,请查看下一篇介绍

        loadDirtectory()方法,会将①Dubbo框架自己实现的一些协议 ②我们自定义的协议,都放入到extensionClass中(然后通过序号15,放入缓存中cacheClasses中),如下图(myProtocol为自定义的协议,其他8项为Dubbo官方实现的协议)

⑯如果获取不到协议的实现类,则会通过动态代理机制,生成自适应适配器扩展点(第⑨步),然后通过 URL 的方式来判断当前服务需要什么协议,然后通过名称来匹配协议即可。End


⑰injectExtension()方法分析

       injectExtension( )方法,在步骤 ⑦ 中使用到,主要是进行依赖注入,此处涉及到 Dubbo 的依赖注入机制。

private T injectExtension(T instance) {
    try {
        if (objectFactory != null) {
            for (Method method : instance.getClass().getMethods()) {
                if (method.getName().startsWith("set")
                        && method.getParameterTypes().length == 1
                        && Modifier.isPublic(method.getModifiers())) {
                    /**
                     * Check {@link DisableInject} to see if we need auto injection for this property
                     */
                    if (method.getAnnotation(DisableInject.class) != null) {
                        continue;
                    }
                    Class<?> pt = method.getParameterTypes()[0];
                    try {
                        String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                        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;
}

       接步骤⑦,我们通过getAdaptiveExtensionClass().newInstance() 可以得到一个当前适配器扩展点的一个实例,然后将该实例传入injectExtension()方法中。

       如果目前加载的是一个扩展点,该扩展点存在一个属性,并存在一个setXXX方法,那么该方法会对当前属性的扩展点进行注入操作。 (此处借助 AdaptiveCompiler 类了解)

@Adaptive
public class AdaptiveCompiler implements Compiler {

    //属性
    private static volatile String DEFAULT_COMPILER;
    //set方法
    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }
    //根据set方法传入的名称,通过ExtensionLoader.getExtensionLoader(xxx.class)方法,去调用对应扩展点的compile方法
    @Override
    public Class<?> compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

    //该扩展点本身是一个自适应扩展点,它没有实现,而是通过加载的方式去实现的。
    //如果当前加载的扩展点或自适应扩展点,存在一个setXXX方法,set方法对应的属性是一个扩展点的话,injectExtension()方法会以这种方式进行依赖注入
}

 AdaptiveCompiler类,在类级别上使用@Adaptive,说明当前类是一个自定义的扩展点。

 @Adaptive   可以使用在类上,也可以使用在方法上;
       1.如果是配置在类级别上,表示自定义适配器(injectExtension()方法直接加载当前自适应的类)
       2.如果是配置在方法级别上,会动态创建一个自定义适配器

       在步骤⑧中,如果ExtensionLoader.getExtensionLoader()加载的是Compiler这个扩展点。第一次加载时,检测到@Adaptive是在类层面上,则会直接进入 if 条件,返回cachedAdaptiveClass,而不会通过动态代理来创建一个适配器扩展点;如果@Adaptive 是在方法层面上,则会通过动态代理,来创建适配器扩展点。(动态代理生成的代码,见序号⑨中)


Dubbo源码分析----ExtensionLoader模块,介绍到此为止

如果本文对你有所帮助,那就给我点个赞呗 ^_^ 

End

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扛麻袋的少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值