精盡 Dubbo 源碼分析 —— 過濾器(一)之 ClassLoaderFilter

1.概述

在 ProtocolFilterWrapper 中,在服務引用和暴露時,#buildInvokerChain(invoker, key, group) 方法中,基於 Dubbo SPI Active 機制,加載匹配對應的過濾器數組,創建帶有過濾器鏈的 Invoker 對象。代碼如下:

/**
 * 創建帶 Filter 鏈的 Invoker 對象
 *
 * @param invoker Invoker 對象
 * @param key 獲取 URL 參數名
 * @param group 分組
 * @param <T> 泛型
 * @return Invoker 對象
 */
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    // 獲得過濾器數組
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    // 倒序循環 Filter ,創建帶 Filter 鏈的 Invoker 對象
    if (!filters.isEmpty()) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {

                @Override
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }

                @Override
                public URL getUrl() {
                    return invoker.getUrl();
                }

                @Override
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }

                @Override
                public Result invoke(Invocation invocation) throws RpcException {
                    return filter.invoke(next, invocation);
                }

                @Override
                public void destroy() {
                    invoker.destroy();
                }

                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

2.ClassLoaderFilter

實現 Filter 接口,類加載器切換過濾器實現類。代碼如下:

@Activate(group = Constants.PROVIDER, order = -30000)
public class ClassLoaderFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 獲得原來的類加載器
        ClassLoader ocl = Thread.currentThread().getContextClassLoader();
        // 切換當前線程的類加載器爲服務接口的類加載器
        Thread.currentThread().setContextClassLoader(invoker.getInterface().getClassLoader());
        // 服務調用
        try {
            return invoker.invoke(invocation);
        } finally {
            // 切換當前線程的類加載器爲原來的類加載器
            Thread.currentThread().setContextClassLoader(ocl);
        }
    }

}

作用是在設計目的中,切換到加載了接口定義的類加載器,以便實現與相同的類加載器上下文一起工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章