???本文重点讲述SPI机制,从jdk和dubbo
1、jdk spi机制
2、dubbo spi实现
首先spi是什么?
SPI是为某个接口寻找服务实现的机制。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
其次java spi是怎么找到实现类的?
java spi和所有实现接口的厂商有一个俗称的约定,只要将META-INF/services文件夹下生成一个和抽象类全名称(路径+类名称)相同的配置文件,那么厂商的jar包只要在工程路径下就能找到实现类。这种方式主要是解决不同厂商不同实现类的加载问题。在不修改java文件的情况下,如何才能够定位到不同的实现类。
JDK的spi机制有一个缺点,就是如果多个厂商的spi实现的jar包都在路径下,那么就要加载所有的实现类,这样很浪费资源。dubbo中每一种接口都有很多种实现,如果使用jdk这种方式自然做不到优雅的根据一个接口来获得该接口的实现。dubbo的目标就是:根据你配置的name获取某一个特定的接口实现,没有用到的其他接口实现就不能被实例化,免得浪费。因此,dubbo就按照SPI机制的原理自己实现了一套扩展机制。为实现dubbo的扩展机制,dubbo的SPI做到了一下三个方面。
1 可以方便的获取某一个想要的扩展实现,java的SPI机制就没有提供这样的功能
2 对于扩展实现IOC 依赖注入功能
3 对扩展采用装饰器模式进行功能增强,类似AOP实现的功能
dubbo的SPI实现具体如下。
首先定义一个SPI注解类
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
/**
* 缺省扩展点名。
*/
String value() default "";
}
dubbo里面很多的接口都打了SPI注解,这些注解的实现要从一下三个文件夹下去寻找实现。
META-INF/dubbo/internal/ //dubbo内部实现的各种扩展都放在了这个目录了
META-INF/dubbo
/META-INF/services/
文件里面的内容全部都是key-value的形式存在。dubbo的各种接口有很多类型的实现。拿Protocol举例,它的实现:DubboProtocol InjvmProtocolHessianProtocol WebServiceProtocol等等。dubbo的扩展机制如何去查找你的实现类,并实现调用的呢?
ExtensionLoader<T>
拿ServiceConfig<T>中的这两个变量举例子。
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
这两个变量最终生成的既不是接口也不是具体的实现类,而是一个接口适配器类。这个适配器类动态的生成的,如下所示的代码:
package com.alibaba.dubbo.rpc; import com.alibaba.dubbo.common.extension.ExtensionLoader; public class ProxyFactory$Adpative implements com.alibaba.dubbo.rpc.ProxyFactory { public java.lang.Object getProxy(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.getParameter("proxy", "javassist"); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])"); //根据url的信息去获取真实的实现类 com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getProxy(arg0); } public com.alibaba.dubbo.rpc.Invoker getInvoker(java.lang.Object arg0, java.lang.Class arg1, com.alibaba.dubbo.common.URL arg2) throws java.lang.Object { if (arg2 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg2; String extName = url.getParameter("proxy", "javassist"); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url(" + url.toString() + ") use keys([proxy])"); com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName); return extension.getInvoker(arg0, arg1, arg2); } }
首先,我们来看适配器类是如何生成
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
第一步:通过proxyFactory.class类型生成一个ExtensionLoader<T>实例。
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) { ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); if (loader == null) {每个定义的spi的接口都会构建一个ExtensionLoader实例,存储在EXTENSION_LOADERS EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type)); loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type); } return loader;}
第二步:创建Adaptive实例,放入数组cachedAdaptiveInstance中。
public T getAdaptiveExtension() { Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if(createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try {//创建Adaptive实例,放入数组cachedAdaptiveInstance中。 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; }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); } }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();//编译这个类适配器为class文件 return compiler.compile(code, classLoader); } // 此方法已经getExtensionClasses方法同步过。 private Map<String, Class<?>> loadExtensionClasses() {//先读取SPI注解的value值,有值作为默认扩展实现的key final SPI defaultAnnotation = type.getAnnotation(SPI.class); if(defaultAnnotation != null) { 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<?>>();//读取三个文件夹下的文件,将key-class放置到extensionClasses中 loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY); loadFile(extensionClasses, DUBBO_DIRECTORY); loadFile(extensionClasses, SERVICES_DIRECTORY); return extensionClasses; } private void loadFile(Map<String, Class<?>> extensionClasses, String dir) { //获取文件路径 目录+type名称 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); //判断实现类是否实现了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)) { //将打了Adaptive注解的类放置到cachedAdaptiveClass 中去。 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 { //判断该是否有实现类是否存在入参为接口的构造器 clazz.getConstructor(type); Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } //按照装饰器的角色将该类加进来 wrappers.add(clazz); } // end of while urls } } catch (Throwable t) { logger.error("Exception when load extension class(interface: " + type + ", description file: " + fileName + ").", t); } }
适配器中发现这个实现类也是由这个方法生成extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName)
//创建扩展类 instance = createExtension(name); 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, (T) clazz.newInstance());//获取该实例数据对 instance = (T) EXTENSION_INSTANCES.get(clazz); }//set注入参数 injectExtension(instance);//获取包装器类。 class com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper class com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0) { 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); } }
dubbo的SPI扩展机制,使得我们给出url就能动态的去获取真实的实现类。获得到真实的实现类,是实现功能的第一步。下面我们来看看spring如何加载到dubbo解析器类,并将dubbo功能收入囊下的。未完待续。
参考文献
http://m.blog.csdn.net/blog/u010311445/41577235
原文:http://my.oschina.net/zjItLife/blog/530923