Dubbo的自適應擴展點和激活擴展點

  • 上篇文章寫了一下spi在java和spiring中的實現,以及Dubbo中的靜態擴展點文章鏈接,這裏接着把Dubbo的自適應擴展點和激活擴展點看完
  • 這裏還是上篇的dubbo測試類
public class DubboSpi {
    public static void main(String[] args) {
        //靜態擴展點
        Container myContainer = ExtensionLoader.getExtensionLoader(Container.class).getExtension("myContainer");
        System.out.println(myContainer);
        //輸出:com.test.spi.dubbo.MyContainer@6aa8ceb6

        //自適應擴展點,加在類上和加載方法上
        Compiler adaptiveExtension = ExtensionLoader.getExtensionLoader(Compiler.class).getAdaptiveExtension();
        System.out.println(adaptiveExtension);

        //輸出:org.apache.dubbo.common.compiler.support.AdaptiveCompiler@759ebb3d
        Protocol adaptiveExtension1 = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
        System.out.println(adaptiveExtension1);
        //輸出:org.apache.dubbo.rpc.Protocol$Adaptive@61a485d2


        //激活擴展點
        URL url = new URL("","localhost",8080).addParameters(Constants.DEPRECATED_KEY,Constants.DEPRECATED_KEY);
        List<Filter> activateExtension = ExtensionLoader.getExtensionLoader(Filter.class)
                .getActivateExtension(url, Constants.DEPRECATED_KEY);
        System.out.println(activateExtension);
        //輸出:[org.apache.dubbo.rpc.filter.EchoFilter@69ea3742, org.apache.dubbo.rpc.filter.ClassLoaderFilter@4b952a2d, org.apache.dubbo.rpc.filter.GenericFilter@3159c4b8, org.apache.dubbo.rpc.filter.ConsumerContextFilter@73846619, org.apache.dubbo.rpc.filter.ContextFilter@4bec1f0c, org.apache.dubbo.rpc.protocol.dubbo.filter.FutureFilter@29ca901e, org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter@5649fd9b, org.apache.dubbo.rpc.filter.TimeoutFilter@6adede5, org.apache.dubbo.monitor.support.MonitorFilter@2d928643, org.apache.dubbo.rpc.filter.ExceptionFilter@5025a98f, org.apache.dubbo.cache.filter.CacheFilter@49993335]
    }
}

自適應擴展點

我們可以看到自適應擴展點有2種,一種是@Adaptive加載類上,一種是@Adaptive加載方法上,加載方法上的比較簡單,我們從getAdaptiveExtension()開始看起,調用路線如下

  • getAdaptiveExtension()
    • createAdaptiveExtension()
      • getAdaptiveExtensionClass() 之後我們還會回到這裏
        • getExtensionClasses()
          • loadExtensionClasses()
            • loadDirectory()
              • loadResource()
                • loadClass() 這裏就是查看@Adaptive加在類上的關鍵地方了
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) 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.");
        }
        //如果類上有@Adaptive註解,就就如cacheAdaptiveClass()方法
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            cacheAdaptiveClass(clazz);
        } else if (isWrapperClass(clazz)) {
            cacheWrapperClass(clazz);
        } else {
          .... 省略
    }
    
    private void cacheAdaptiveClass(Class<?> clazz) {
    	//這裏要記住,我們給一個成員變量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());
        }
    }
  • 我們回到上面走方法流程標記要回到的方法getAdaptiveExtensionClass,@Adaptive加在到類上的加載就完成了
private Class<?> getAdaptiveExtensionClass() {
        getExtensionClasses();
        //在上面的cacheAdaptiveClass中我們給這個變量賦過值,所以就可以直接返回了
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        //加載在方法上
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
@Adaptive加載方法上的時候
  • 還是getAdaptiveExtensionClass()開始
  • getAdaptiveExtensionClass()
    • createAdaptiveExtensionClass()
private Class<?> createAdaptiveExtensionClass() {
		//通過拼接字符的方式生成代碼,可以看下面的圖
        String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
        ClassLoader classLoader = findClassLoader();
        //通過一個Compiler的自適應擴展點AdaptiveCompiler動態生成類
        org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

在這裏插入圖片描述
這就是Protocol這個類動態生成的代碼,可以看到代碼還是比較簡單的,通過一個靜態擴展點選擇不同的類執行export等方法,到這裏加在方法上的自適應擴展點也看完了

激活擴展點

  • 查看的方法路徑
  • getActivateExtension() 之後我們還會回到這裏
    • getExtensionClasses()
      • getAdaptiveExtensionClass()
        • loadExtensionClasses()
          • loadDirectory()
            • loadResource()
              • loadClass()
  • 還是在loadClass中
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        ...省略
            String[] names = NAME_SEPARATOR.split(name);
            if (ArrayUtils.isNotEmpty(names)) {
            //這裏獲取緩存激活擴展點
                cacheActivateClass(clazz, names[0]);
                for (String n : names) {
                    cacheName(clazz, n);
                    saveInExtensionClass(extensionClasses, clazz, name);
                }
            }
        }
        
private void cacheActivateClass(Class<?> clazz, String name) {
		//如果類上有@Activate註解,就把他加在緩存cachedActivates中
        Activate activate = clazz.getAnnotation(Activate.class);
        if (activate != null) {
            cachedActivates.put(name, activate);
        } else {
            // support com.alibaba.dubbo.common.extension.Activate
            com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
            if (oldActivate != null) {
                cachedActivates.put(name, oldActivate);
            }
        }
    }
  • 之後我們回到getActivateExtension(URL url, String[] values, String group)中
public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<>();
        List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
        if (!names.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
            getExtensionClasses();
            //這裏就是在激活擴展點的加載,cachedActivates就是我們上面緩存的
            for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Object activate = entry.getValue();

                String[] activateGroup, activateValue;

                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;
                }
                //先匹配group,在匹配擴展點中寫的value,匹配到了就加入集合中返回
                if (isMatchGroup(group, activateGroup)) {
                    T ext = getExtension(name);
                    if (!names.contains(name)
                            && !names.contains(REMOVE_VALUE_PREFIX + name)
                            && isActive(activateValue, url)) {
                            
                        exts.add(ext);
                    }
                }
            }
            exts.sort(ActivateComparator.COMPARATOR);
        }
        List<T> usrs = 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 (!usrs.isEmpty()) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        if (!usrs.isEmpty()) {
            exts.addAll(usrs);
        }
        return exts;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章