SPI,即(service provider interface)机制,有不少组件的实现,如日志、数据库访问等都是采用这样的方式,通常通用组件为了提高可扩展性,基于接口编程,将操做接口造成标准规范,可是能够开放多种扩展实现,这种作法也符合开闭设计原则,使组件具备可插拨特性。不一样的厂商或组织能够基于规范推出本身的实现,只须要在本身的jar包中经过配置文件和相应的实现类便可以实现扩展。甚至开发者本身也能够很方便对框架进行定制化实现。java
JDK实现spi服务查找: ServiceLoader。
举个例子:
首先定义下示例接口数据库
package com.example; public interface Spi { booleanisSupport(String name); String sayHello(); }
ServiceLoader会遍历全部jar查找META-INF/services/com.example.Spi文件apache
A厂商提供实现编程
package com.a.example; public class SpiAImpl implements Spi { publicboolean isSupport(String name) { return"SPIA".equalsIgnoreCase(name.trim()); } public String syaHello() { return “hello 我是厂商A”; } }
在A厂商提供的jar包中的META-INF/services/com.example.Spi文件内容为:缓存
com.a.example.SpiAImpl #厂商A的spi实现全路径类名安全
B厂商提供实现app
package com.b.example; public class SpiBImpl implements Spi { publicboolean isSupport(String name) { return"SPIB".equalsIgnoreCase(name.trim()); } public String syaHello() { return “hello 我是厂商B”; } }
在B厂商提供的jar包中的META-INF/services/com.example.Spi文件内容为:框架
com.b.example.SpiBImpl #厂商B的spi实现全路径类名ide
ServiceLoader.load(Spi.class)读取厂商A、B提供jar包中的文件,ServiceLoader实现了Iterable接口可经过while for循环语句遍历出全部实现。函数
一个接口多种实现,就如策略模式同样提供了策略的实现,可是没有提供策略的选择, 使用方能够根据isSupport方法根据业务传入厂商名来选择具体的厂商。
public class SpiFactory { //读取配置获取全部实现 privatestatic ServiceLoader spiLoader = ServiceLoader.load(Spi.class); //根据名字选取对应实现 publicstatic Spi getSpi(String name) { for(Spi spi : spiLoader) { if(spi.isSupport(name) ) { returnspi; } } returnnull; } }
Dubbo 改进了 JDK 标准的 SPI 的如下问题:
在扩展类的jar包内,放置扩展点配置文件 META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
以扩展 Dubbo 的协议为例,在协议的实现 jar 包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:
xxx=com.alibaba.xxx.XxxProtocol
实现类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocol implemenets Protocol { // ... }
dubbo扩展机制的实现核心类是ExtensionLoad,几乎全部扩展实现都在这个类里面。每一个可扩展接口的扩展实现类和实现实例的都管理经过是ExtensionLoad进行,每一个接口维护一个单例的ExtensionLoad,全部可扩展接口的实现都维护在ExtensionLoad中,以下所示:
/** * SPI 类和ExtensionLoader映射 */ private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
在单例模式中,最典型的实现就是经过私有构造方法实现的:
private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
在dubbo扩展点实现过程当中,有几个重要的特性须要提早了解一下:
自动包装扩展点的 Wrapper 类。ExtensionLoader 在加载扩展点时,若是加载到的扩展点有拷贝构造函数,则断定为扩展点 Wrapper 类。
Wrapper类内容:
package com.alibaba.xxx; import com.alibaba.dubbo.rpc.Protocol; public class XxxProtocolWrapper implemenets Protocol { Protocol impl; public XxxProtocol(Protocol protocol) { impl = protocol; } // 接口方法作一个操做后,再调用extension的方法 public void refer() { //... 一些操做 impl.refer(); // ... 一些操做 } // ... }
Wrapper 类一样实现了扩展点接口,可是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的其实是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。这个是典型的装饰者模式,即真正的实现类是被包装在Wrapper之中,Wrapper类还作一些其它事情。
加载扩展点时,自动注入依赖的扩展点。加载扩展点时,扩展点实现类的成员若是为其它扩展点类型,ExtensionLoader 在会自动注入依赖的扩展点。ExtensionLoader 经过扫描扩展点实现类的全部 setter 方法来断定其成员。即 ExtensionLoader 会执行扩展点的拼装操做。这个相似于Spring的IOC,后面会专门介绍。
在调用过程,自动选择一个扩展实现执行,一个扩展点只容许有一个自适应实现。dubbo经过@Adaptive注解标定自适应实现,这个注解能够在实现类上,也能够在方法上。好比ExtensionFactory的自适应实现就是经过在实现类AdaptiveExtensionFactory上加@Adaptive注解实现的:
@Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { ... }
如 Cluster就是经过在方法加@Adaptive实现的:
@SPI(FailoverCluster.NAME) public interface Cluster { /** * Merge the directory invokers to a virtual invoker. * * @param <T> * @param directory * @return cluster invoker * @throws RpcException */ @Adaptive <T> Invoker<T> join(Directory<T> directory) throws RpcException; }
这两种方式的自适应扩展类的实现方式也不一样,在类上加注解是经过在实现上标识该类为自适应实现类,而在方法上加注解的,是经过动态代码生成自适应实现类。
对于集合类扩展点,好比:Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等,能够同时加载多个实现,此时,能够用自动激活来简化配置
在ExtensionLoader中比较重要的公用方法就是这些:
下面就详细剖析一下ExtensionLoader的实现流程。
每一个可扩展接口对应的ExtensionLoader都是单例,惟一获取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) { EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader; }
会校验尝试获取Loader的接口是否有@SPI注解,先在缓存中找,若是没有缓存,则调用私有构造方法:
private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); }
这里有个重要的对象objectFactory,这个对象的做用就是自动装配依赖,也就是IOC,能够看出,除了ObjectFactory自己,全部扩展点都有ObjectFactory实例,这个也是经过SPI管理的,它是经过getAdaptiveExtension()方法获取,这就是后面要介绍自适应扩展实现,有关ObjectFactory的内容会在后面IOC中详细分析。
咱们从getAdaptiveExtension()方法切入,这个方法要完成的任务就是获取该扩展点的自适应实现实例,其流程以下图所示:
主要完成如下工做:
配置文件配置的自适应类经过在实现类上面加@Adaptive注解,如
..... @Adaptive public class AdaptiveExtensionFactory implements ExtensionFactory { }
字节码生成的自适应实现类是在方法层面@Adaptive注解,如
@SPI("dubbo") public interface Protocol { ....省略代码 @Adaptive <T> Exporter<T> export(Invoker<T> invoker) throws RpcException; @Adaptive <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException; void destroy(); }
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); //配置的实现必须实现该接口 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 { //若是不是自适应类 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) { //找到Extension注解 name = findAnnotationName(clazz); if (name == null || name.length() == 0) { //若是Extension注解没有默认名称,则根据类的名称关系判断 if (clazz.getSimpleName().length() > type.getSimpleName().length() && clazz.getSimpleName().endsWith(type.getSimpleName())) { //若是实现类和接口有名称上关系,好比XXImpl则将后面的做为实现类标识 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 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); } }
private Class<?> getAdaptiveExtensionClass() { //先经过配置文化加载实现类,而且识别自适应实现类 getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } //若是没有经过Adaptive注解标识的自适应实现类,则经过字节码建立 return cachedAdaptiveClass = 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); }
@Adaptive public class AdaptiveCompiler implements Compiler { private static volatile String DEFAULT_COMPILER; public static void setDefaultCompiler(String compiler) { DEFAULT_COMPILER = compiler; } 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); } }
下面是经过字节码动态生成的Protocol接口的自适应扩展Protocol$Adpative:
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); } public void destroyServer() { throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroyServer() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!"); } }
在dubbo中,某些组件能够同时有多个实现同时加载时,就能够经过@Activate注解自动激活,常见的自动激活扩展,如过滤器Filter,有顺序要求,提供了三个排序属性,before、after和order。还有一些过滤条件,主要是经过分组和key,如Provider和consumer的过滤逻辑可能就不同,Activate的源码以下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Activate { /** * Group过滤条件。 */ String[] group() default {}; String[] value() default {}; /** * 排序信息,能够不提供。 */ String[] before() default {}; /** * 排序信息,能够不提供。 */ String[] after() default {}; /** * 排序信息,能够不提供。 */ int order() default 0; }
在ExtensionLoader中,有三个重载获取激活扩展实现的方法:
后面两个也是经过调用第一个重载方法实现,下面来分析一下它的源码:
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); if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) { getExtensionClasses(); for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) { String name = entry.getKey(); Activate activate = entry.getValue(); if (isMatchGroup(group, activate.group())) { T ext = getExtension(name); 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)) { if (Constants.DEFAULT_KEY.equals(name)) { if (usrs.size() > 0) { exts.addAll(0, usrs); usrs.clear(); } } else { T ext = getExtension(name); usrs.add(ext); } } } if (usrs.size() > 0) { exts.addAll(usrs); } return exts; }
这个方法所作的工做无非就是在以前加载配置时缓存的cachedActivates中过滤查询符合条件的自动激动实例,并根据@Activate注解中配置的排序规则排序。
在建立自适应实例时,都会调用ExtensionLoader的injectExtension方法:
private T createAdaptiveExtension() { try { //传入自适应实例注入到ExtensionLoader return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e); } } 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())) { 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; }
而后咱们看到了ExtensionFactory对象,dubbo中的IOC实例是经过ExtensionFactory实现的,其实就是检测扩展实现类有没有经过set方法设置的属性,若是有,就经过ExtensionFactory加载而设置。
ExtensionFactory的类实现体系:
在构造ExtensionLoader对象时,有个对象extensionFactory是必需要建立的,能够看到它就是用自适应实例,而ExtensionFatocry的自适应实例即是AdaptiveExtensionFactory,经过下面它的源码,咱们能够发现,它维护了其余非自适应扩展实例,其实也就两个SpiExtensionFactory和SpringExtensionFactory。尝试用这两个实例去加载,加载到便返回。
@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; } }
ExtensionFatocry 能够理解为对象工厂,只不过这里的对应就是Dubbo中的扩展Extension,AdaptiveExtensionFactory能够理解为通用扩展实现获取的入口,至于具体的获取方式分为两种,若是一种是经过Dubbo 本身的SPI方式加载到的扩展,同时还支持复用Srping 的方式,能够看看这两种实现的代码即可知:
public class SpiExtensionFactory implements ExtensionFactory { 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; } } public class SpringExtensionFactory implements ExtensionFactory { private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>(); public static void addApplicationContext(ApplicationContext context) { contexts.add(context); } public static void removeApplicationContext(ApplicationContext context) { contexts.remove(context); } @SuppressWarnings("unchecked") public <T> T getExtension(Class<T> type, String name) { for (ApplicationContext context : contexts) { if (context.containsBean(name)) { Object bean = context.getBean(name); if (type.isInstance(bean)) { return (T) bean; } } } return null; } }
做为贯穿整个Dubbo设计始终的思想,SPI在整个框架中随处可见,本文围绕ExtensionLoader扩展点机制,经过一些dubbo组件扩展现例,分析了其核心源码和流程。但愿能够对于理解Dubbo的扩展点乃至dubbo源码解析过程当中有所帮助,最后总结几点:
http://dubbo.apache.org/books...
https://blog.csdn.net/jdluoji...