找回密码
 立即注册
首页 业界区 业界 JDK的SPI有什么缺陷?dubbo做了什么改进? ...

JDK的SPI有什么缺陷?dubbo做了什么改进?

摹熹 前天 22:01
JDK的SPI机制的缺点

⽂件中的所有类都会被加载且被实例化。这样也就导致获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。如果不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,没有办法指定某⼀个类来加载和实例化,这就造成了浪费。
此时dubbo的SPI可以解决
dubbo的SPI机制

dubbo⾃⼰实现了⼀套SPI机制来解决Java的SPI机制存在的问题。
dubbo中则采用了类似kv对的样式,在具体使用的时候则通过相关想法即可获取,而且获取的文件路径也不一致
ExtensionLoader 类文件
  1. private static final String SERVICES_DIRECTORY = "META-INF/services/";
  2. private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
  3.    
  4. private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
复制代码
如上述代码片段可知,dubbo是支持从META-INF/dubbo/,META-INF/dubbo/internal/以及META-INF/services/三个文件夹的路径去获取spi配置
1.png

例如com.alibaba.dubbo.rpc.Protocol 文件内容
  1. registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
  2. filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
  3. listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
  4. mock=com.alibaba.dubbo.rpc.support.MockProtocol
  5. injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
  6. dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
  7. rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
  8. hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
  9. com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
  10. com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
  11. thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
  12. memcached=memcom.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
  13. redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
复制代码
不过观察上述文件会发现,HttpProtocol是没有对应的k值,那就是说无法通过kv对获取到其协议实现类。后面通过源码可以发现,如果没有对应的name的时候,dubbo会通过findAnnotationName方法获取一个可用的name
Dubbo SPI 使用 & 源码学习

通过获取协议的代码来分析下具体的操作过程
Protocol 获取

Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
  1. public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
  2.     // 静态方法,意味着可以直接通过类调用
  3.     if (type == null)
  4.         throw new IllegalArgumentException("Extension type == null");
  5.     if(!type.isInterface()) {
  6.         throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
  7.     }
  8.     if(!withExtensionAnnotation(type)) {
  9.         throw new IllegalArgumentException("Extension type(" + type +
  10.                 ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
  11.     }
  12.    
  13.     ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  14.     // 从map中获取该类型的ExtensionLoader数据
  15.     if (loader == null) {
  16.         EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
  17.         // 如果没有则,创建一个新的ExtensionLoader对象,并且以该类型存储
  18.         loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
  19.         // 再从map中获取
  20.         // 这里这样做的原因就是为了防止并发的问题,而且map本是也是个ConcurrentHashMap
  21.     }
  22.     return loader;
  23. }
复制代码
  1. private ExtensionLoader(Class<?> type) {
  2.     this.type = type;
  3.     objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
  4. }
  5. // 传入的type是Protocol.class,所以需要获取ExtensionFactory.class最合适的实现类
复制代码
  1. public T getAdaptiveExtension() {
  2.     Object instance = cachedAdaptiveInstance.get();
  3.     if (instance == null) {
  4.         if(createAdaptiveInstanceError == null) {
  5.             synchronized (cachedAdaptiveInstance) {
  6.                 instance = cachedAdaptiveInstance.get();
  7.                 if (instance == null) {
  8.                     try {
  9.                         instance = createAdaptiveExtension();
  10.                         // 创建对象,也是需要关注的函数
  11.                         cachedAdaptiveInstance.set(instance);
  12.                     } catch (Throwable t) {
  13.                         createAdaptiveInstanceError = t;
  14.                         throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
  15.                     }
  16.                 }
  17.             }
  18.         }
  19.         else {
  20.             throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
  21.         }
  22.     }
  23.     return (T) instance;
  24. }
复制代码
  1. private T createAdaptiveExtension() {
  2.     try {
  3.         return injectExtension((T) getAdaptiveExtensionClass().newInstance());
  4.         // (T) getAdaptiveExtensionClass().newInstance() 创建一个具体的实例对象
  5.         // getAdaptiveExtensionClass() 生成相关的class
  6.         // injectExtension 往该对象中注入数据
  7.     } catch (Exception e) {
  8.         throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
  9.     }
  10. }
复制代码
  1. private Class<?> getAdaptiveExtensionClass() {
  2.     getExtensionClasses();
  3.     // 通过加载SPI配置,获取到需要的所有的实现类存储到map中
  4.     // 通过可能会去修改cachedAdaptiveClass数据,具体原因在spi配置文件解析中分析
  5.     if (cachedAdaptiveClass != null) {
  6.         return cachedAdaptiveClass;
  7.     }
  8.     return cachedAdaptiveClass = createAdaptiveExtensionClass();
  9. }
复制代码
  1. private Class<?> createAdaptiveExtensionClass() {
  2.     String code = createAdaptiveExtensionClassCode();
  3.     // 动态生成需要的代码内容字符串
  4.     ClassLoader classLoader = findClassLoader();
  5.     com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  6.     return compiler.compile(code, classLoader);
  7.     // 编译,生成相应的类
  8. }
复制代码
如下代码Protocol$Adpative 整个的类就是通过createAdaptiveExtensionClassCode()方法生成的一个大字符串
  1. public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {  
  2.     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!");  
  3.     }  
  4.     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!");  
  5.     }  
  6.     public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {  
  7.         // 暴露远程服务,传入的参数是invoke对象
  8.         if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");  
  9.   
  10.         if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");  
  11.   
  12.         com.alibaba.dubbo.common.URL url = arg0.getUrl();  
  13.   
  14.         String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );  
  15.         // 如果没有具体协议,则使用dubbo协议
  16.   
  17.         if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");  
  18.   
  19.         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);  
  20.   
  21.         return extension.export(arg0);  
  22.     }  
  23.     public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {  
  24.         // 引用远程对象,生成相对应的远程invoke对象
  25.         if (arg1 == null) throw new IllegalArgumentException("url == null");  
  26.   
  27.         com.alibaba.dubbo.common.URL url = arg1;  
  28.   
  29.         String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );  
  30.   
  31.         if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");  
  32.   
  33.         com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);  
  34.   
  35.         return extension.refer(arg0, arg1);  
  36.     }  
  37. }  
复制代码
到现在可以认为是最上面的获取protocol的方法Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension() 返回了一个代码拼接而成然后编译操作的实现类Protocol$Adpative
可是得到具体的实现呢?在com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName)这个代码中,当然这个是有在具体的暴露服务或者引用远程服务才被调用执行的。
  1. public T getExtension(String name) {
  2.     if (name == null || name.length() == 0)
  3.         throw new IllegalArgumentException("Extension name == null");
  4.     if ("true".equals(name)) {
  5.         return getDefaultExtension();
  6.     }
  7.     Holder<Object> holder = cachedInstances.get(name);
  8.     if (holder == null) {
  9.         cachedInstances.putIfAbsent(name, new Holder<Object>());
  10.         holder = cachedInstances.get(name);
  11.     }
  12.     // 无论是否真有数据,在cachedInstances存储的是一个具体的Holder对象
  13.     Object instance = holder.get();
  14.     if (instance == null) {
  15.         synchronized (holder) {
  16.             instance = holder.get();
  17.             if (instance == null) {
  18.                 instance = createExtension(name);
  19.                 // 创建对象
  20.                 holder.set(instance);
  21.             }
  22.         }
  23.     }
  24.     return (T) instance;
  25. }
复制代码
[code]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());            // clazz.newInstance 才是真正创建对象的操作            instance = (T) EXTENSION_INSTANCES.get(clazz);        }        injectExtension(instance);        // 往实例中反射注入参数        Set> loadExtensionClasses() {    final SPI defaultAnnotation = type.getAnnotation(SPI.class);    // 查看该类是否存在SPI注解信息    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];            // 设置默认的名称,如果注解的值经过切割,发现超过1个的数据,则同样会认为错误        }    }        Map>();    loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);    // 加载文件    loadFile(extensionClasses, DUBBO_DIRECTORY);    loadFile(extensionClasses, SERVICES_DIRECTORY);    return extensionClasses;}    private void loadFile(Map
您需要登录后才可以回帖 登录 | 立即注册