• dubbo源码分析4——SPI机制_ExtensionFactory类的作用


    ExtensionFactory的源码:

    @SPI
    public interface ExtensionFactory {
    
        /**
         * Get extension.
         * 
         * @param type object type.
         * @param name object name.
         * @return object instance.
         */
        <T> T getExtension(Class<T> type, String name);
    
    }

    ExtensionFactory的作用就类似spring框架中的IOC的作用,正是因为JDK的SPI机制比较简单,所以duboo框架才重写了SPI机制,并实现了IOC和AOP的功能。本篇先介绍它的IOC的功能,根据上篇的分析可知,IOC功能的代码出现在ExtensionLoader的 injectExtension方法里面,我们就先来分析这个方法,先列出两段源码:

    触发调用injectExtension方法的源码:

    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);
                }
                injectExtension(instance);  //完成IOC的依赖注入
                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);
            }
        }
        

     injectExtension方法的源码:

    private T injectExtension(T instance) {  //instanceSPI实现类的实例对象 

        try {
          
    if (objectFactory != null) {
              //获取instance的所有方法,
                    for (Method method : instance.getClass().getMethods()) {
                //找出满足三要素条件的方法(1.set为前缀的 2.方法参数为1个的 3.是public的方法)
    if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 && Modifier.isPublic(method.getModifiers())) { Class<?> pt = method.getParameterTypes()[0]; //获取要 set的类型 try {
                     //取出要 set的属性名 String property
    = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : ""; Object object = objectFactory.getExtension(pt, property); //调用ExtensionFactory的
    getExtension方法获取要set的对象               
                    
                    
    //此时我们就可以将
    ExtensionFactory看作容器,判断这个要set的属性在容器中是否存在
                    if (object != null) { 
                      method.invoke(instance, object);   //执行set方法,完成一个属性的注入
                    }
                  }
    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;
    }

    上面的源码通过注释已经把injectExtension 方法分析的很清楚了,下面只需要再分析下AdaptiveExtensionFactory类的源码就可以了,原因上篇文章也写明了,因为所有的SPI类(除ExtensionFactory之外)对应的ExtensionLoader实例的objectFactory属性的类型都是AdaptiveExtensionFactory类

    AdaptiveExtensionFactory类的构造方法分析: 

     根据 loadFile()方法的缓存原则,AdaptiveExtensionFactory实例中的factories的size返回应为2,里面只会保存这两个类实例:

        spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory

      spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

    因为adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory是保存在cachedAdaptiveClass上的

    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);
        }

    这样我们只要分析清楚AdaptiveExtensionFactory类的getExtension方法,就可以明白这个IOC容器是如何取出需要的SPI实例依赖了

    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;
        }

    从上述代码上看其实就去调用下面这两个类的getExtension(type, name)方法

    com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory

    com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

    SpringExtensionFactory的源码:

    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")
    //这个比较容易理解,就是从spring的容器中去获取
    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; } }

    SpiExtensionFactory的源码 :

     看了这个方法真是觉的挺绕的,明明先是ExtensionLoader在注入时找自己的 objectFactory ( 即ExtensionFactory)来帮忙,结果objectFactory的这个实现,又把锅甩回给了loader.getAdaptiveExtension()方法,由于这个getAdaptiveExtension就又回到了之前讲过的一个调用过程,这里再列一下:

    getAdaptiveExtension()内部的调用过程如下(注意这是一个实例方法):

    -> if(cachedAdaptiveInstance.get() == null){ createAdaptiveExtension() }

          ->getAdaptiveExtensionClass()   //下面的调用有两个分支

                  // 分支1
        ->getExtensionClasses()
          ->loadExtensionClasses()
            ->loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);

            injectExtension   //完成注入,这是 ExtensionFactory 类的作用之所在 

                   // 分支2

                   ->createAdaptiveExtensionClass()

                      injectExtension 

    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;
        }
    
    }

    总结:

       通过跟踪源码,以目前的这几个实现类而言,SpiExtensionFactory其实啥都没干,最后还是loader.getAdaptiveExtension()方法在负责IOC,SpiExtensionFactory只可以理解成是一个门面类的作用。

  • 相关阅读:
    fatal: unable to access 'https://github.com/github-eliviate/papers.git/': Failed to connect to github.com port 443 after 21107 ms: Timed out
    ImportError: attempted relative import with no known parent package
    python 创建中文目录
    pyodbc.InterfaceError: ('IM002', '[IM002] [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序 (0) (SQLDriverConnect)')
    pyodbc.InterfaceError: ('28000', '[28000] 用户 'sa' 登录失败。 (18456) 无法打开登录所请求的数据库 "ARCHIVEDB"。登录失败。
    pyodbc.OperationalError: ('08001', '[08001] 无法打开与 SQL Server 的连接[08001]登录超时已过期 (0); 与 SQL Server 建立连接时发生了与网络相关的或特定于实例的错误。找不到或无法访问服务器。请检查实例名称是否正确以及 SQL Server 是否配置为允许远程连接。
    医学图像分割论文:Swin-Unet—Unet-like Pure Transformer for Medical Image Segmentation_202105.05537
    网络请求例子
    blog.devtang.com
    nsdata
  • 原文地址:https://www.cnblogs.com/hzhuxin/p/7553070.html
Copyright © 2020-2023  润新知