前一篇文章《dubbo源码解析(一)Hello,Dubbo》是对dubbo整个项目大致的介绍,而从这篇文章开始,我将会从源码来解读dubbo再各个模块的实现原理以及特色,因为所有由截图的方式去解读源码会致使文章很杂乱,因此我只会放部分截图,所有的解读会同步更新在我github上fork的dubbo源码中,同时我也会在文章一些关键的地方加上超连接,方便读者快速查阅。html
我会在以后的每篇文章前都写一个目标,为了让读者一眼就能知道本文是不是你须要寻找的资料。java
目标:让读者知道JDK的SPI思想,dubbo的SPI思想,dubbo扩展机制SPI的原理,可以读懂实现扩展机制的源码。
第一篇源码分析的文章就先来说讲dubbo扩展机制spi的原理,浏览过dubbo官方文档的朋友确定知道,dubbo有大量的spi扩展实现,包括协议扩展、调用拦截扩展、路由扩展等26个扩展,而且spi机制运用到了各个模块设计中。因此我打算先讲解dubbo的扩展机制spi。git
SPI的全名为Service Provider Interface,面向对象的设计里面,模块之间推荐基于接口编程,而不是对实现类进行硬编码,这样作也是为了模块设计的可拔插原则。为了在模块装配的时候不在程序里指明是哪一个实现,就须要一种服务发现的机制,jdk的spi就是为某个接口寻找服务实现。jdk提供了服务实现查找的工具类:java.util.ServiceLoader,它会去加载META-INF/service/目录下的配置文件。具体的内部实现逻辑为这里先不展开,主要仍是讲解dubbo关于spi的实现原理。github
dubbo本身实现了一套SPI机制,改进了JDK标准的SPI机制:apache
咱们先来看看SPI扩展机制实现的结构目录:编程
在某个接口上加上@SPI注解后,代表该接口为可扩展接口。我用协议扩展接口Protocol来举例子,若是使用者在<dubbo:protocol />、<dubbo:service />、<dubbo:reference />都没有指定protocol属性的话,那么就会默认DubboProtocol就是接口Protocol,由于在Protocol上有@SPI("dubbo")注解。而这个protocol属性值或者默认值会被看成该接口的实现类中的一个key,dubbo会去META-INFdubbointernalcom.alibaba.dubbo.rpc.Protocol文件中找该key对应的value,看下图:segmentfault
value就是该Protocol接口的实现类DubboProtocol,这样就作到了SPI扩展。数组
该注解为了保证dubbo在内部调用具体实现的时候不是硬编码来指定引用哪一个实现,也就是为了适配一个接口的多种实现,这样作符合模块接口设计的可插拔原则,也增长了整个框架的灵活性,<u>该注解也实现了扩展点自动装配的特性</u>。缓存
dubbo提供了两种方式来实现接口的适配器:微信
举个例子dubbo中的ExtensionFactory接口就有一个实现类AdaptiveExtensionFactory,加了@Adaptive注解,AdaptiveExtensionFactory就不提供具体业务支持,用来适配ExtensionFactory的SpiExtensionFactory和SpringExtensionFactory这两种实现。AdaptiveExtensionFactory会根据在运行时的一些状态来选择具体调用ExtensionFactory的哪一个实现,具体的选择能够看下文Adaptive的代码解析。
咱们从Transporter接口的源码来解释这种方法:
咱们能够看到在这个接口的bind和connect方法上都有@Adaptive注解,有该注解的方法的参数必须包含URL,ExtensionLoader会经过createAdaptiveExtensionClassCode方法动态生成一个Transporter$Adaptive类,生成的代码以下:
package com.alibaba.dubbo.remoting; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class Transporter$Adaptive implements com.alibaba.dubbo.remoting.Transporter{ public com.alibaba.dubbo.remoting.Client connect(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.remoting.ChannelHandler arg1) throws com.alibaba.dubbo.remoting.RemotingException { //URL参数为空则抛出异常。 if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; //这里的getParameter方法能够在源码中具体查看 String extName = url.getParameter("client", url.getParameter("transporter", "netty")); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" + url.toString() + ") use keys([client, transporter])"); //这里我在后面会有详细介绍 com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter)ExtensionLoader.getExtensionLoader (com.alibaba.dubbo.remoting.Transporter.class).getExtension(extName); return extension.connect(arg0, arg1); } public com.alibaba.dubbo.remoting.Server bind(com.alibaba.dubbo.common.URL arg0, com.alibaba.dubbo.remoting.ChannelHandler arg1) throws com.alibaba.dubbo.remoting.RemotingException { if (arg0 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg0; String extName = url.getParameter("server", url.getParameter("transporter", "netty")); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.remoting.Transporter) name from url(" + url.toString() + ") use keys([server, transporter])"); com.alibaba.dubbo.remoting.Transporter extension = (com.alibaba.dubbo.remoting.Transporter)ExtensionLoader.getExtensionLoader (com.alibaba.dubbo.remoting.Transporter.class).getExtension(extName); return extension.bind(arg0, arg1); } }
能够看到该类的两个方法就是Transporter接口中有注解的两个方法,我来解释一下第一个方法connect:
这样就比较清楚这个适配器如何去选择哪一个实现类做为本次须要调用的类,这里最关键的仍是强调了dubbo以URL为总线,运行过程当中全部的状态数据信息均可以经过URL来获取,好比当前系统采用什么序列化,采用什么通讯,采用什么负载均衡等信息,都是经过URL的参数来呈现的,因此在框架运行过程当中,运行到某个阶段须要相应的数据,均可以经过对应的Key从URL的参数列表中获取。
扩展点自动激活加载的注解,就是用条件来控制该扩展点实现是否被自动激活加载,在扩展实现类上面使用,<u>实现了扩展点自动激活的特性</u>,它能够设置两个参数,分别是group和value。具体的介绍能够参照官方文档。
扩展点自动激活地址: http://dubbo.apache.org/zh-cn...
先来看看它的源码:
该接口是扩展工厂接口类,它自己也是一个扩展接口,有SPI的注解。该工厂接口提供的就是获取实现类的实例,它也有两种扩展实现,分别是SpiExtensionFactory和SpringExtensionFactory表明着两种不一样方式去获取实例。而具体选择哪一种方式去获取实现类的实例,则在适配器AdaptiveExtensionFactory中制定了规则。具体规则看下面的源码解析。
该类是扩展加载器,这是dubbo实现SPI扩展机制等核心,几乎全部实现的逻辑都被封装在ExtensionLoader中。
详细代码注释见github: https://github.com/CrazyHZM/i...
关于存放配置文件的路径变量:
private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
"META-INF/services/"、"META-INF/dubbo/"、"META-INF/dubbo/internal/"三个值,都是dubbo寻找扩展实现类的配置文件存放路径,也就是我在上述(一)注解@SPI中讲到的以接口全限定名命名的配置文件存放的路径。区别在于"META-INF/services/"是dubbo为了兼容jdk的SPI扩展机制思想而设存在的,"META-INF/dubbo/internal/"是dubbo内部提供的扩展的配置文件路径,而"META-INF/dubbo/"是为了给用户自定义的扩展实现配置文件存放。
扩展加载器集合,key为扩展接口,例如Protocol等:
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
扩展实现类集合,key为扩展实现类,value为扩展对象,例如key为Class<DubboProtocol>,value为DubboProtocol对象
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
如下属性都是cache开头的,都是出于性能和资源的优化,才作的缓存,读取扩展配置后,会先进行缓存,等到真正须要用到某个实现时,再对该实现类的对象进行初始化,而后对该对象也进行缓存。
//如下提到的扩展名就是在配置文件中的key值,相似于“dubbo”等 //缓存的扩展名与拓展类映射,和cachedClasses的key和value对换。 private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>(); //缓存的扩展实现类集合 private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>(); //扩展名与加有@Activate的自动激活类的映射 private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>(); //缓存的扩展对象集合,key为扩展名,value为扩展对象 //例如Protocol扩展,key为dubbo,value为DubboProcotol private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object //缓存的自适应( Adaptive )扩展对象,例如例如AdaptiveExtensionFactory类的对象 private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>(); //缓存的自适应扩展对象的类,例如AdaptiveExtensionFactory类 private volatile Class<?> cachedAdaptiveClass = null; //缓存的默认扩展名,就是@SPI中设置的值 private String cachedDefaultName; //建立cachedAdaptiveInstance异常 private volatile Throwable createAdaptiveInstanceError; //拓展Wrapper实现类集合 private Set<Class<?>> cachedWrapperClasses; //拓展名与加载对应拓展类发生的异常的映射 private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
这里提到了Wrapper类的概念。那我就解释一下:Wrapper类也实现了扩展接口,可是Wrapper类的用途是ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外,<u>这实现了扩展点自动包装的特性</u>。通俗点说,就是一个接口有不少的实现类,这些实现类会有一些公共的逻辑,若是在每一个实现类写一遍这个公共逻辑,那么代码就会重复,因此增长了这个Wrapper类来包装,把公共逻辑写到Wrapper类中,有点相似AOP切面编程思想。这部分解释也能够结合官方文档:
扩展点自动包装的特性地址: http://dubbo.apache.org/zh-cn...
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { //扩展点接口为空,抛出异常 if (type == null) throw new IllegalArgumentException("Extension type == null"); //判断type是不是一个接口类 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); //若是为空,则建立该扩展接口的扩展加载器,而且添加到EXTENSION_LOADERS if (loader == null) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
这个方法的源码解析看上面,解读起来仍是没有太多难点的。就是把几个属性的含义弄清楚就行了。
public List<T> getActivateExtension(URL url, String key) { return getActivateExtension(url, key, null); } //弃用 public List<T> getActivateExtension(URL url, String[] values) { return getActivateExtension(url, values, null); } public List<T> getActivateExtension(URL url, String key, String group) { String value = url.getParameter(key); // 得到符合自动激活条件的拓展对象数组 return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group); } public List<T> getActivateExtension(URL url, String[] values, String group) { List<T> exts = new ArrayList<T>(); List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values); //判断不存在配置 `"-name"` 。 //例如,<dubbo:service filter="-default" /> ,表明移除全部默认过滤器。 if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { //得到扩展实现类数组,把扩展实现类放到cachedClasses中 getExtensionClasses(); for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); //判断group值是否存在全部自动激活类中group组中,匹配分组 if (isMatchGroup(group, activate.group())) { //经过扩展名得到拓展对象 T ext = getExtension(name); //不包含在自定义配置里。若是包含,会在下面的代码处理。 //判断是否配置移除。例如 <dubbo:service filter="-monitor" />,则 MonitorFilter 会被移除 //判断是否激活 if (!names.contains(name) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) { exts.add(ext); } } } //排序 Collections.sort(exts, ActivateComparator.COMPARATOR); } List<T> usrs = new ArrayList<T>(); for (int i = 0; i < names.size(); i++) { String name = names.get(i); //仍是判断是不是被移除的配置 if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { //在配置中把自定义的配置放在自动激活的扩展对象前面,可让自定义的配置先加载 //例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。 if (Constants.DEFAULT_KEY.equals(name)) { if (!usrs.isEmpty()) { exts.addAll(0, usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (!usrs.isEmpty()) { exts.addAll(usrs); } return exts; }
能够看到getActivateExtension重载了四个方法,其实最终的实现都是在最后一个重载方法,由于自动激活类的条件能够分为无条件、只有value以及有group和value三种,具体的能够回顾上述(三)注解@Activate。
最后一个getActivateExtension方法有几个关键点:
@SuppressWarnings("unchecked") public T getExtension(String name) { if (name == null || name.length() == 0) throw new IllegalArgumentException("Extension name == null"); //查找默认的扩展实现,也就是@SPI中的默认值做为key 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; }
这个方法中涉及到getDefaultExtension方法和createExtension方法,会在后面讲到。其余逻辑比较简单,就是从缓存中取,若是没有,就建立,而后放入缓存。
public T getDefaultExtension() { //得到扩展接口的实现类数组 getExtensionClasses(); if (null == cachedDefaultName || cachedDefaultName.length() == 0 || "true".equals(cachedDefaultName)) { return null; } //又从新去调用了getExtension return getExtension(cachedDefaultName); }
这里涉及到getExtensionClasses方法,会在后面讲到。得到默认的扩展实现类对象就是经过缓存中默认的扩展名去得到实现类对象。
public void addExtension(String name, Class<?> clazz) { getExtensionClasses(); // load classes //该类是不是接口的自己或子类 if (!type.isAssignableFrom(clazz)) { throw new IllegalStateException("Input type " + clazz + "not implement Extension " + type); } //该类是否被激活 if (clazz.isInterface()) { throw new IllegalStateException("Input type " + clazz + "can not be interface!"); } //判断是否为适配器 if (!clazz.isAnnotationPresent(Adaptive.class)) { if (StringUtils.isBlank(name)) { throw new IllegalStateException("Extension name is blank (Extension " + type + ")!"); } if (cachedClasses.get().containsKey(name)) { throw new IllegalStateException("Extension name " + name + " already existed(Extension " + type + ")!"); } //把扩展名和扩展接口的实现类放入缓存 cachedNames.put(clazz, name); cachedClasses.get().put(name, clazz); } else { if (cachedAdaptiveClass != null) { throw new IllegalStateException("Adaptive Extension already existed(Extension " + type + ")!"); } cachedAdaptiveClass = clazz; } }
@SuppressWarnings("unchecked") 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; }
思路就是先从缓存中取适配器类的对象,若是没有,则建立一个适配器对象,而后放入缓存,createAdaptiveExtension方法解释在后面给出。
@SuppressWarnings("unchecked") private T createExtension(String 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); } //向对象中注入依赖的属性(自动装配) injectExtension(instance); //建立 Wrapper 扩展对象(自动包装) Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && !wrapperClasses.isEmpty()) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } return instance; } catch (Throwable t) { throw new IllegalStateException("Extension instance(name: " + name + ", class: " + type + ") could not be instantiated: " + t.getMessage(), t); } }
这里运用到了两个扩展点的特性,分别是自动装配和自动包装。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 { //得到属性,好比StubProxyFactoryWrapper类中有Protocol protocol属性, String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; //得到属性值,好比Protocol对象,也多是Bean对象 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; }
思路就是是先经过反射得到类中的全部方法,而后找到set方法,找到须要依赖注入的属性,而后把对象注入进去。
private Class<?> getExtensionClass(String name) { if (type == null) throw new IllegalArgumentException("Extension type == null"); if (name == null) throw new IllegalArgumentException("Extension name == null"); Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) throw new IllegalStateException("No such extension \"" + name + "\" for " + type.getName() + "!"); return clazz; }
这边就是调用了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方法解析在下面给出。
loadExtensionClasses方法:从配置文件中,加载拓展实现类数组
private Map<String, Class<?>> loadExtensionClasses() { final SPI defaultAnnotation = type.getAnnotation(SPI.class); if (defaultAnnotation != null) { //@SPI内的默认值 String value = defaultAnnotation.value(); if ((value = value.trim()).length() > 0) { String[] names = NAME_SEPARATOR.split(value); //只容许有一个默认值 if (names.length > 1) { throw new IllegalStateException("more than 1 default extension name on extension " + type.getName() + ": " + Arrays.toString(names)); } if (names.length == 1) cachedDefaultName = names[0]; } } //从配置文件中加载实现类数组 Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>(); loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadDirectory(extensionClasses, DUBBO_DIRECTORY); loadDirectory(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; }
前一部分逻辑是在把SPI注解中的默认值放到缓存中去,加载实现类数组的逻辑是在后面几行,关键的就是loadDirectory方法(解析在下面给出),而且这里能够看出去找配置文件访问的资源路径顺序。
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) { //拼接接口全限定名,获得完整的文件名 String fileName = dir + type.getName(); try { Enumeration<java.net.URL> urls; //获取ExtensionLoader类信息 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(); loadResource(extensionClasses, classLoader, resourceURL); } } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
这边的思路是先得到完整的文件名,遍历每个文件,在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跟value name = line.substring(0, i).trim(); line = line.substring(i + 1).trim(); } if (line.length() > 0) { //加载扩展类 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); } }
该类的主要的逻辑就是读取里面的内容,跳过“#”注释的内容,根据配置文件中的key=value的形式去分割,而后去加载value对应的类。
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException { //该类是否实现扩展接口 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."); } //判断该类是否为扩展接口的适配器 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)) { Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } else { //经过反射得到构造器对象 clazz.getConstructor(); //未配置扩展名,自动生成,例如DemoFilter为 demo,主要用于兼容java SPI的配置。 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()); } } } } }
重点关注该方法中兼容了jdk的SPI思想。由于jdk的SPI相关的配置文件中是xx.yyy.DemoFilter,并无key,也就是没有扩展名的概念,全部为了兼容,经过xx.yyy.DemoFilter生成的扩展名为demo。
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方法中,createAdaptiveExtensionClassCode方法因为过长,我不在这边列出,下面会给出github的网址,读者可自行查看相关的源码解析。createAdaptiveExtensionClassCode生成的代码逻辑能够对照我上述讲的(二)注解@Adaptive中的Transporter$Adpative类来看。
ExtensionLoader类源码解析地址: https://github.com/CrazyHZM/i...
该类是ExtensionFactory的适配器类,也就是我在(二)注解@Adaptive中提到的第一种适配器类的使用。来看看该类的源码:
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { //扩展对象的集合,默认的能够分为dubbo 的SPI中接口实现类对象或者Spring bean对象 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); } @Override public <T> T getExtension(Class<T> type, String name) { for (ExtensionFactory factory : factories) { //经过扩展接口和扩展名得到扩展对象 T extension = factory.getExtension(type, name); if (extension != null) { return extension; } } return null; } }
SPI ExtensionFactory 拓展实现类,看看源码:
public class SpiExtensionFactory implements ExtensionFactory { @Override public <T> T getExtension(Class<T> type, String name) { //判断是否为接口,接口上是否有@SPI注解 if (type.isInterface() && type.isAnnotationPresent(SPI.class)) { //得到扩展加载器 ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type); if (!loader.getSupportedExtensions().isEmpty()) { //返回适配器类的对象 return loader.getAdaptiveExtension(); } } return null; } }
该类在ExtensionLoader类的getActivateExtension方法中被运用到,做为自动激活拓展对象的排序器。
public class ActivateComparator implements Comparator<Object> { public static final Comparator<Object> COMPARATOR = new ActivateComparator(); @Override public int compare(Object o1, Object o2) { //基本排序 if (o1 == null && o2 == null) { return 0; } if (o1 == null) { return -1; } if (o2 == null) { return 1; } if (o1.equals(o2)) { return 0; } Activate a1 = o1.getClass().getAnnotation(Activate.class); Activate a2 = o2.getClass().getAnnotation(Activate.class); //使用Activate注解的 `after` 和 `before` 属性,排序 if ((a1.before().length > 0 || a1.after().length > 0 || a2.before().length > 0 || a2.after().length > 0) && o1.getClass().getInterfaces().length > 0 && o1.getClass().getInterfaces()[0].isAnnotationPresent(SPI.class)) { ExtensionLoader<?> extensionLoader = ExtensionLoader.getExtensionLoader(o1.getClass().getInterfaces()[0]); if (a1.before().length > 0 || a1.after().length > 0) { String n2 = extensionLoader.getExtensionName(o2.getClass()); for (String before : a1.before()) { if (before.equals(n2)) { return -1; } } for (String after : a1.after()) { if (after.equals(n2)) { return 1; } } } if (a2.before().length > 0 || a2.after().length > 0) { String n1 = extensionLoader.getExtensionName(o1.getClass()); for (String before : a2.before()) { if (before.equals(n1)) { return 1; } } for (String after : a2.after()) { if (after.equals(n1)) { return -1; } } } } // 使用Activate注解的 `order` 属性,排序。 int n1 = a1 == null ? 0 : a1.order(); int n2 = a2 == null ? 0 : a2.order(); // never return 0 even if n1 equals n2, otherwise, o1 and o2 will override each other in collection like HashSet return n1 > n2 ? 1 : -1; } }
关键的仍是经过@Activate注解中的值来进行排序。
该部分相关的源码解析地址: https://github.com/CrazyHZM/i...
该文章讲解了dubbo的SPI扩展机制的实现原理,最关键的是弄清楚dubbo跟jdk在实现SPI的思想上作了哪些改进和优化,解读dubbo SPI扩展机制最关键的是弄清楚@SPI、@Adaptive、@Activate三个注解的含义,大部分逻辑都被封装在ExtensionLoader类中。dubbo的不少接口都是扩展接口,解读该文,也能让读者在后续文章中更加容易的去了解dubbo的架构设计。若是我在哪一部分写的不够到位或者写错了,欢迎给我提意见,个人私人微信号码:HUA799695226。