美文网首页
(SPI)3.dubbo spi代码分析

(SPI)3.dubbo spi代码分析

作者: 无聊之园 | 来源:发表于2021-10-26 14:48 被阅读0次

    看三个方法,静态扩展类,adapter扩展类,activate扩展类。
    先看getExtension

            Protocol dubbo = ExtensionLoader.getExtensionLoader(Protocol.class)
                    .getExtension("dubbo");
    
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
            // 维护了一个缓存,多次调用获取扩展器不会重复new
            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;
        }
    
    // 1、ExtensionLoader会维护一个objectFactory,objectFactory也是spi机制获取的
    //spi依赖注入的时候,会通过objectFactory获取到其他的spi对象注入进去
    //2、获取到的可适配扩展对象AdaptiveExtensionFactory效果就是遍历所有的
    //ExtensionFactory实现类来获取对象。
    // 3、ExtensionFactory有两个具体的实现类SpringExtensionFactory,
    // SpiExtensionFactory。一个是从SPI获取,一个是从spring容器获取对象。所以说
    // spi的依赖注入的时候,会从这两个地方获取对象注入进去。
    // 4、相关SpiExtensionFactory、SpringExtensionFactory代码比较简单,不贴了
        private ExtensionLoader(Class<?> type) {
            this.type = type;
            objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
        }
    @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);
        }
    
        @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;
        }
    
    }
    

    获取实现类对象,通过名称。
    这里有个小设计值得说一下,这里使用了Holder包裹了instance。假设直接缓存instance如下。则为了防止并发,多次扫描创建对象,则需要锁住整个cacheInstances缓存。而使用Holder包裹一下,则只需要锁住Holder就可以了

    T instance = cachedInstances.get(name);
    if (instance == null){
        synchronized(cacheInstances){
          instance  = cachedInstances.get(name);
          if(instance == null){
            // 创建对象
          }
      }
    }
    
     public T getExtension(String name) {
            final Holder<Object> holder = getOrCreateHolder(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;
        }
    
    private T createExtension(String name) {
          // getExtensionClasses方法会真正扫描meta-inf文件并加载class
            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);
                Set<Class<?>> wrapperClasses = cachedWrapperClasses;
                if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                    for (Class<?> wrapperClass : wrapperClasses) {
                        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                    }
                }
              // 初始化。如果对象实现类Lifecycle生命周期接口,则调用这个接口的初始化方法initialize
                initExtension(instance);
                return instance;
            } catch (Throwable t) {
                throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                        type + ") couldn't be instantiated: " + t.getMessage(), t);
            }
        }
    
     private Map<String, Class<?>> loadExtensionClasses() {
            cacheDefaultExtensionName();
    
            Map<String, Class<?>> extensionClasses = new HashMap<>();
    
            for (LoadingStrategy strategy : strategies) {
                loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
                loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
            }
    
            return extensionClasses;
        }
    

    Dubbo的spi的获取加载策略,是通过java的spi获取的。

     private static volatile LoadingStrategy[] strategies = loadLoadingStrategies();
    
       private static LoadingStrategy[] loadLoadingStrategies() {
            return stream(load(LoadingStrategy.class).spliterator(), false)
                    .sorted()
                    .toArray(LoadingStrategy[]::new);
        }
    
    image.png

    3个LoadingStrategy,分别指定了不同的目录。

    public class DubboLoadingStrategy implements LoadingStrategy {
    
        @Override
        public String directory() {
            return "META-INF/dubbo/";
        }
    
        @Override
        public boolean overridden() {
            return true;
        }
    
        @Override
        public int getPriority() {
            return NORMAL_PRIORITY;
        }
    
    
    }
    

    分析是否存在Adaptive注解:用成员变量维护Adaptive的class
    是否是WrapperClass(构造方法传参是Type这个接口类型):用成员变量维护
    如果存在Extension注解(这个注解自定义name)
    是否存在Activate注解,是则缓存起来:用map维护。
    缓存所有的class。

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
                               boolean overridden) throws NoSuchMethodException {
            if (!type.isAssignableFrom(clazz)) {
                throw new IllegalStateException("Error occurred when loading extension class (interface: " +
                        type + ", class line: " + clazz.getName() + "), class "
                        + clazz.getName() + " is not subtype of interface.");
            }
            if (clazz.isAnnotationPresent(Adaptive.class)) {
                cacheAdaptiveClass(clazz, overridden);
            } else if (isWr55¥¥apperClass(clazz)) {
                cacheWrapperClass(clazz);
            } else {
                clazz.getConstructor();
                if (StringUtils.isEmpty(name)) {
                    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 (ArrayUtils.isNotEmpty(names)) {
                    cacheActivateClass(clazz, names[0]);
                    for (String n : names) {
                        cacheName(clazz, n);
                        saveInExtensionClass(extensionClasses, clazz, n, overridden);
                    }
                }
            }
        }
    

    injectExtension,依赖注入就是遍历set方法,用objectFactory从spi或spring中获取需要的对象注入进去。

    private T injectExtension(T instance) {
    
            if (objectFactory == null) {
                return instance;
            }
    
            try {
                for (Method method : instance.getClass().getMethods()) {
                    if (!isSetter(method)) {
                        continue;
                    }
                    /**
                     * Check {@link DisableInject} to see if we need auto injection for this property
                     */
                    if (method.getAnnotation(DisableInject.class) != null) {
                        continue;
                    }
                    Class<?> pt = method.getParameterTypes()[0];
                    if (ReflectUtils.isPrimitives(pt)) {
                        continue;
                    }
    
                    try {
                        String property = getSetterProperty(method);
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            method.invoke(instance, object);
                        }
                    } catch (Exception e) {
                        logger.error("Failed to inject via method " + method.getName()
                                + " of interface " + type.getName() + ": " + e.getMessage(), e);
                    }
    
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            return instance;
        }
    

    至此,getExtension方法看完了。

    看一下getAdaptiveExtension获取自适应扩展类。
    主要代码:

    public T getAdaptiveExtension() {
            Object instance = cachedAdaptiveInstance.get();
            if (instance == null) {
                   synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
      // 前面说了在加载meta-inf配置文件然后加载Class类的时候,如果类上有
    //@Adaptive注解,就会把这个类赋值给cachedAdaptiveInstance。
     // 所以如果这里为空,则会创建一个代理类,不为空,则直接把加了@Adaptive的类返回。
                   if (instance == null) {
                        try {
                            instance = createAdaptiveExtension();
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            }
    
            return (T) instance;
        }
    
    private Class<?> createAdaptiveExtensionClass() {
           // 生成代码,编译加载
            String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
            ClassLoader classLoader = findClassLoader();
            org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
            return compiler.compile(code, classLoader);
        }
    

    动态生成的代理类代码大概如下,会根据url参数动态指定调用哪个实现类的方法。

    public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
        public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, 
                                                  org.apache.dubbo.common.URL arg1) 
                throws org.apache.dubbo.rpc.RpcException {
            if (arg1 == null) throw new IllegalArgumentException("url == null");
            org.apache.dubbo.common.URL url = arg1;
            String extName = (url.getProtocol() == null 
                    ? "dubbo" : url.getProtocol());
            org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) 
                    ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class)
                            .getExtension(extName);
            return extension.refer(arg0, arg1);
        }
    

    至此getAdaptiveExtension也看完了。
    再看看getActivateExtension方法。

            URL url = new URL("", "", 0);
            url = url.addParameter("ab", "cache");
            List<Filter> filters = loader.getActivateExtension(url, "ab");
    
      public List<T> getActivateExtension(URL url, String key, String group) {
          // 从url中以传入的参数key,获取指定的value
            String value = url.getParameter(key);
            return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
        }
    
     public List<T> getActivateExtension(URL url, String[] values, String group) {
            List<T> activateExtensions = new ArrayList<>();
            List<String> names = values == null ? new ArrayList<>(0) : asList(values);
            if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
            // 扫描和加载class   
             getExtensionClasses();
                for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
                    // 扩展类的名字,比如cacheFilter,name就是cache
                    String name = entry.getKey();
                    // Activate注解对象
                    Object activate = entry.getValue();
    
                    String[] activateGroup, activateValue;
                // 先添加group匹配,name
                    if (activate instanceof Activate) {
                        activateGroup = ((Activate) activate).group();
                        activateValue = ((Activate) activate).value();
                    } else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
                        activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
                        activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
                    } else {
                        continue;
                    }
    // 座一层适配过滤
                    if (isMatchGroup(group, activateGroup)
                            && !names.contains(name)
                            && !names.contains(REMOVE_VALUE_PREFIX + name)
                            && isActive(activateValue, url)) {
                        activateExtensions.add(getExtension(name));
                    }
                }
                activateExtensions.sort(ActivateComparator.COMPARATOR);
            }
    // 再根据传参,把扩展类后添加进来,比如传参cache,cacheFilter就会在这里后添加进来
            List<T> loadedExtensions = new ArrayList<>();
            for (int i = 0; i < names.size(); i++) {
                String name = names.get(i);
                if (!name.startsWith(REMOVE_VALUE_PREFIX)
                        && !names.contains(REMOVE_VALUE_PREFIX + name)) {
                    if (DEFAULT_KEY.equals(name)) {
                        if (!loadedExtensions.isEmpty()) {
                            activateExtensions.addAll(0, loadedExtensions);
                            loadedExtensions.clear();
                        }
                    } else {
                        loadedExtensions.add(getExtension(name));
                    }
                }
            }
            if (!loadedExtensions.isEmpty()) {
                activateExtensions.addAll(loadedExtensions);
            }
            return activateExtensions;
        }
    

    相关文章

      网友评论

          本文标题:(SPI)3.dubbo spi代码分析

          本文链接:https://www.haomeiwen.com/subject/btaealtx.html