国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

dubbo源碼解析(四十一)集群——Mock

ivydom / 1430人閱讀

摘要:源碼分析一創(chuàng)建該類是服務(wù)降級的裝飾器類,對進(jìn)行了功能增強(qiáng),增強(qiáng)了服務(wù)降級的功能。注意隱式契約盡管描述被添加到接口聲明中,但是可擴(kuò)展性是一個問題。獲得服務(wù)類型獲得創(chuàng)建加入集合該方法是獲得。

集群——Mock
目標(biāo):介紹dubbo中集群的Mock,介紹dubbo-cluster下關(guān)于服務(wù)降級和本地偽裝的源碼。
前言

本文講解兩塊內(nèi)容,分別是本地偽裝和服務(wù)降級,本地偽裝通常用于服務(wù)降級,比如某驗權(quán)服務(wù),當(dāng)服務(wù)提供方全部掛掉后,客戶端不拋出異常,而是通過 Mock 數(shù)據(jù)返回授權(quán)失敗。而服務(wù)降級則是臨時屏蔽某個出錯的非關(guān)鍵服務(wù),并定義降級后的返回策略。

源碼分析 (一)MockClusterWrapper
public class MockClusterWrapper implements Cluster {

    private Cluster cluster;

    public MockClusterWrapper(Cluster cluster) {
        this.cluster = cluster;
    }

    @Override
    public  Invoker join(Directory directory) throws RpcException {
        // 創(chuàng)建MockClusterInvoker
        return new MockClusterInvoker(directory,
                this.cluster.join(directory));
    }

}

該類是服務(wù)降級的裝飾器類,對Cluster進(jìn)行了功能增強(qiáng),增強(qiáng)了服務(wù)降級的功能。

(二)MockClusterInvoker

該類是服務(wù)降級中定義降級后的返回策略的實現(xiàn)。

1.屬性
private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);

/**
 * 目錄
 */
private final Directory directory;

/**
 * invoker對象
 */
private final Invoker invoker;
2.invoke
@Override
public Result invoke(Invocation invocation) throws RpcException {
    Result result = null;

    // 獲得 "mock" 配置項,有多種配置方式
    String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
    // 如果沒有mock
    if (value.length() == 0 || value.equalsIgnoreCase("false")) {
        //no mock
        // 直接調(diào)用
        result = this.invoker.invoke(invocation);
        // 如果強(qiáng)制服務(wù)降級
    } else if (value.startsWith("force")) {
        if (logger.isWarnEnabled()) {
            logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
        }
        //force:direct mock
        // 直接調(diào)用 Mock Invoker ,執(zhí)行本地 Mock 邏輯
        result = doMockInvoke(invocation, null);
    } else {
        //fail-mock
        // 失敗服務(wù)降級
        try {
            // 否則正常調(diào)用
            result = this.invoker.invoke(invocation);
        } catch (RpcException e) {
            if (e.isBiz()) {
                throw e;
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                }
                // 如果調(diào)用失敗,則服務(wù)降級
                result = doMockInvoke(invocation, e);
            }
        }
    }
    return result;
}

該方法是定義降級后的返回策略的實現(xiàn),根據(jù)配置的不同來決定不用降級還是強(qiáng)制服務(wù)降級還是失敗后再服務(wù)降級。

3.doMockInvoke
@SuppressWarnings({"unchecked", "rawtypes"})
private Result doMockInvoke(Invocation invocation, RpcException e) {
    Result result = null;
    Invoker minvoker;

    // 路由匹配 Mock Invoker 集合
    List> mockInvokers = selectMockInvoker(invocation);
    // 如果mockInvokers為空,則創(chuàng)建一個MockInvoker
    if (mockInvokers == null || mockInvokers.isEmpty()) {
        // 創(chuàng)建一個MockInvoker
        minvoker = (Invoker) new MockInvoker(directory.getUrl());
    } else {
        // 取出第一個
        minvoker = mockInvokers.get(0);
    }
    try {
        // 調(diào)用invoke
        result = minvoker.invoke(invocation);
    } catch (RpcException me) {
        // 如果拋出異常,則返回異常結(jié)果
        if (me.isBiz()) {
            result = new RpcResult(me.getCause());
        } else {
            throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
        }
    } catch (Throwable me) {
        throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
    }
    return result;
}

該方法是執(zhí)行本地Mock,服務(wù)降級。

4.selectMockInvoker
private List> selectMockInvoker(Invocation invocation) {
    List> invokers = null;
    //TODO generic invoker?
    if (invocation instanceof RpcInvocation) {
        //Note the implicit contract (although the description is added to the interface declaration, but extensibility is a problem. The practice placed in the attachement needs to be improved)
        // 注意隱式契約(盡管描述被添加到接口聲明中,但是可擴(kuò)展性是一個問題。附件中的做法需要改進(jìn))
        ((RpcInvocation) invocation).setAttachment(Constants.INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
        //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
        // 如果調(diào)用中存在Constants.INVOCATION_NEED_MOCK,則目錄將返回正常調(diào)用者列表,否則,將返回模擬調(diào)用者列表。
        try {
            invokers = directory.list(invocation);
        } catch (RpcException e) {
            if (logger.isInfoEnabled()) {
                logger.info("Exception when try to invoke mock. Get mock invokers error for service:"
                        + directory.getUrl().getServiceInterface() + ", method:" + invocation.getMethodName()
                        + ", will contruct a new mock with "new MockInvoker()".", e);
            }
        }
    }
    return invokers;
}

該方法是路由匹配 Mock Invoker 集合。

(三)MockInvokersSelector

該類是路由選擇器實現(xiàn)類。

1.route
@Override
public  List> route(final List> invokers,
                                  URL url, final Invocation invocation) throws RpcException {
    // 如果附加值為空,則直接
    if (invocation.getAttachments() == null) {
        // 獲得普通的invoker集合
        return getNormalInvokers(invokers);
    } else {
        // 獲得是否需要降級的值
        String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
        // 如果為空,則獲得普通的Invoker集合
        if (value == null)
            return getNormalInvokers(invokers);
        else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
            // 獲得MockedInvoker集合
            return getMockedInvokers(invokers);
        }
    }
    return invokers;
}

該方法是根據(jù)配置來決定選擇普通的invoker集合還是mockInvoker集合。

2.getMockedInvokers
private  List> getMockedInvokers(final List> invokers) {
    // 如果沒有MockedInvoker,則返回null
    if (!hasMockProviders(invokers)) {
        return null;
    }
    // 找到MockedInvoker,往sInvokers中加入,并且返回
    List> sInvokers = new ArrayList>(1);
    for (Invoker invoker : invokers) {
        if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
            sInvokers.add(invoker);
        }
    }
    return sInvokers;
}

該方法是獲得MockedInvoker集合。

3.getNormalInvokers
private  List> getNormalInvokers(final List> invokers) {
    // 如果沒有MockedInvoker,則返回普通的Invoker 集合
    if (!hasMockProviders(invokers)) {
        return invokers;
    } else {
        // 否則 去除MockedInvoker,把普通的Invoker 集合返回
        List> sInvokers = new ArrayList>(invokers.size());
        for (Invoker invoker : invokers) {
            // 把不是MockedInvoker的invoker加入sInvokers,返回
            if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
                sInvokers.add(invoker);
            }
        }
        return sInvokers;
    }
}

該方法是獲得普通的Invoker集合,不包含mock的。

4.hasMockProviders
private  boolean hasMockProviders(final List> invokers) {
    boolean hasMockProvider = false;
    for (Invoker invoker : invokers) {
        // 如果有一個是MockInvoker,則返回true
        if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
            hasMockProvider = true;
            break;
        }
    }
    return hasMockProvider;
}

該方法是判斷是否有MockInvoker。

以上三個類是對服務(wù)降級功能的實現(xiàn),下面兩個類是對本地偽裝的實現(xiàn)。

(四)MockProtocol

該類實現(xiàn)了AbstractProtocol接口,是服務(wù)

final public class MockProtocol extends AbstractProtocol {

    @Override
    public int getDefaultPort() {
        return 0;
    }

    @Override
    public  Exporter export(Invoker invoker) throws RpcException {
        throw new UnsupportedOperationException();
    }

    @Override
    public  Invoker refer(Class type, URL url) throws RpcException {
        // 創(chuàng)建MockInvoker
        return new MockInvoker(url);
    }
}
(五)MockInvoker

本地偽裝的invoker實現(xiàn)類。

1.屬性
/**
 * 代理工廠
 */
private final static ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
/**
 * mock 與 Invoker 對象的映射緩存
 */
private final static Map> mocks = new ConcurrentHashMap>();
/**
 * 異常集合
 */
private final static Map throwables = new ConcurrentHashMap();

/**
 * url對象
 */
private final URL url;
2.parseMockValue
public static Object parseMockValue(String mock, Type[] returnTypes) throws Exception {
    Object value = null;
    // 如果mock為empty,則
    if ("empty".equals(mock)) {
        // 獲得空的對象
        value = ReflectUtils.getEmptyObject(returnTypes != null && returnTypes.length > 0 ? (Class) returnTypes[0] : null);
    } else if ("null".equals(mock)) {
        // 如果為null,則返回null
        value = null;
    } else if ("true".equals(mock)) {
        // 如果為true,則返回true
        value = true;
    } else if ("false".equals(mock)) {
        // 如果為false,則返回false
        value = false;
    } else if (mock.length() >= 2 && (mock.startsWith(""") && mock.endsWith(""")
            || mock.startsWith(""") && mock.endsWith("""))) {
        // 使用 "" 或 "" 的字符串,截取掉頭尾
        value = mock.subSequence(1, mock.length() - 1);
    } else if (returnTypes != null && returnTypes.length > 0 && returnTypes[0] == String.class) {
        // 字符串
        value = mock;
    } else if (StringUtils.isNumeric(mock)) {
        // 是數(shù)字
        value = JSON.parse(mock);
    } else if (mock.startsWith("{")) {
        // 是map類型的
        value = JSON.parseObject(mock, Map.class);
    } else if (mock.startsWith("[")) {
        // 是數(shù)組類型
        value = JSON.parseObject(mock, List.class);
    } else {
        value = mock;
    }
    if (returnTypes != null && returnTypes.length > 0) {
        value = PojoUtils.realize(value, (Class) returnTypes[0], returnTypes.length > 1 ? returnTypes[1] : null);
    }
    return value;
}

該方法是解析mock值

3.invoke
@Override
public Result invoke(Invocation invocation) throws RpcException {
    // 獲得 `"mock"` 配置項,方法級 > 類級
    String mock = getUrl().getParameter(invocation.getMethodName() + "." + Constants.MOCK_KEY);
    if (invocation instanceof RpcInvocation) {
        ((RpcInvocation) invocation).setInvoker(this);
    }
    // 如果mock為空
    if (StringUtils.isBlank(mock)) {
        // 獲得mock值
        mock = getUrl().getParameter(Constants.MOCK_KEY);
    }

    // 如果還是為空。則拋出異常
    if (StringUtils.isBlank(mock)) {
        throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
    }
    // 標(biāo)準(zhǔn)化 `"mock"` 配置項
    mock = normalizeMock(URL.decode(mock));
    // 等于 "return " ,返回值為空的 RpcResult 對象
    if (mock.startsWith(Constants.RETURN_PREFIX)) {
        // 分割
        mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
        try {
            // 獲得返回類型
            Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
            // 解析mock值
            Object value = parseMockValue(mock, returnTypes);
            return new RpcResult(value);
        } catch (Exception ew) {
            throw new RpcException("mock return invoke error. method :" + invocation.getMethodName()
                    + ", mock:" + mock + ", url: " + url, ew);
        }
        // 如果是throw
    } else if (mock.startsWith(Constants.THROW_PREFIX)) {
        // 根據(jù)throw分割
        mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
        // 如果為空,則拋出異常
        if (StringUtils.isBlank(mock)) {
            throw new RpcException("mocked exception for service degradation.");
        } else { // user customized class
            // 創(chuàng)建自定義異常
            Throwable t = getThrowable(mock);
            // 拋出業(yè)務(wù)類型的 RpcException 異常
            throw new RpcException(RpcException.BIZ_EXCEPTION, t);
        }
    } else { //impl mock
        try {
            // 否則直接獲得invoker
            Invoker invoker = getInvoker(mock);
            // 調(diào)用
            return invoker.invoke(invocation);
        } catch (Throwable t) {
            throw new RpcException("Failed to create mock implementation class " + mock, t);
        }
    }
}

該方法是本地偽裝的核心實現(xiàn),mock分三種,分別是return、throw、自定義的mock類。

4.normalizedMock
public static String normalizeMock(String mock) {
    // 若為空,直接返回
    if (mock == null) {
        return mock;
    }

    mock = mock.trim();

    if (mock.length() == 0) {
        return mock;
    }

    if (Constants.RETURN_KEY.equalsIgnoreCase(mock)) {
        return Constants.RETURN_PREFIX + "null";
    }

    // 若果為 "true" "default" "fail" "force" 四種字符串,返回default
    if (ConfigUtils.isDefault(mock) || "fail".equalsIgnoreCase(mock) || "force".equalsIgnoreCase(mock)) {
        return "default";
    }

    // fail:throw/return foo => throw/return
    if (mock.startsWith(Constants.FAIL_PREFIX)) {
        mock = mock.substring(Constants.FAIL_PREFIX.length()).trim();
    }

    // force:throw/return foo => throw/return
    if (mock.startsWith(Constants.FORCE_PREFIX)) {
        mock = mock.substring(Constants.FORCE_PREFIX.length()).trim();
    }

    // 如果是return或者throw,替換`為"
    if (mock.startsWith(Constants.RETURN_PREFIX) || mock.startsWith(Constants.THROW_PREFIX)) {
        mock = mock.replace("`", """);
    }

    return mock;
}

該方法是規(guī)范化mock值。

5.getThrowable
public static Throwable getThrowable(String throwstr) {
    // 從異常集合中取出異常
    Throwable throwable = throwables.get(throwstr);
    // 如果不為空,則拋出異常
    if (throwable != null) {
        return throwable;
    }

    try {
        Throwable t;
        // 獲得異常類
        Class bizException = ReflectUtils.forName(throwstr);
        Constructor constructor;
        // 獲得構(gòu)造方法
        constructor = ReflectUtils.findConstructor(bizException, String.class);
        // 創(chuàng)建 Throwable 對象
        t = (Throwable) constructor.newInstance(new Object[]{"mocked exception for service degradation."});
        // 添加到緩存中
        if (throwables.size() < 1000) {
            throwables.put(throwstr, t);
        }
        return t;
    } catch (Exception e) {
        throw new RpcException("mock throw error :" + throwstr + " argument error.", e);
    }
}

該方法是獲得異常。

6.getInvoker
private Invoker getInvoker(String mockService) {
    // 從緩存中,獲得 Invoker 對象,如果有,直接緩存。
    Invoker invoker = (Invoker) mocks.get(mockService);
    if (invoker != null) {
        return invoker;
    }

    // 獲得服務(wù)類型
    Class serviceType = (Class) ReflectUtils.forName(url.getServiceInterface());
    // 獲得MockObject
    T mockObject = (T) getMockObject(mockService, serviceType);
    // 創(chuàng)建invoker
    invoker = proxyFactory.getInvoker(mockObject, serviceType, url);
    if (mocks.size() < 10000) {
        // 加入集合
        mocks.put(mockService, invoker);
    }
    return invoker;
}

該方法是獲得invoker。

7.getMockObject
public static Object getMockObject(String mockService, Class serviceType) {
    if (ConfigUtils.isDefault(mockService)) {
        mockService = serviceType.getName() + "Mock";
    }

    // 獲得類型
    Class mockClass = ReflectUtils.forName(mockService);
    if (!serviceType.isAssignableFrom(mockClass)) {
        throw new IllegalStateException("The mock class " + mockClass.getName() +
                " not implement interface " + serviceType.getName());
    }

    try {
        // 初始化
        return mockClass.newInstance();
    } catch (InstantiationException e) {
        throw new IllegalStateException("No default constructor from mock class " + mockClass.getName(), e);
    } catch (IllegalAccessException e) {
        throw new IllegalStateException(e);
    }
}

該方法是獲得mock對象。

后記
該部分相關(guān)的源碼解析地址:https://github.com/CrazyHZM/i...

該文章講解了集群中關(guān)于mock實現(xiàn)的部分,到這里為止,集群部分就全部講完了,這是2.6.x版本的集群,那在2.7中對于路由和配置規(guī)則都有相應(yīng)的大改動,我會在之后2.7版本的講解中講到。接下來我將開始對序列化模塊進(jìn)行講解。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/73265.html

相關(guān)文章

  • dubbo源碼解析四十六)消費端發(fā)送請求過程

    摘要:可以參考源碼解析二十四遠(yuǎn)程調(diào)用協(xié)議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠(yuǎn)程通信層的四。二十的可以參考源碼解析十七遠(yuǎn)程通信的一。 2.7大揭秘——消費端發(fā)送請求過程 目標(biāo):從源碼的角度分析一個服務(wù)方法調(diào)用經(jīng)歷怎么樣的磨難以后到達(dá)服務(wù)端。 前言 前一篇文章講到的是引用服務(wù)的過程,引用服務(wù)無非就是創(chuàng)建出一個代理。供消費者調(diào)用服務(wù)的相關(guān)方法。...

    fish 評論0 收藏0
  • dubbo源碼解析四十集群——router

    摘要:源碼分析一創(chuàng)建一個該類是基于條件表達(dá)式規(guī)則路由工廠類。路由工廠獲得配置項,默認(rèn)為獲得獲得類型讀取規(guī)則獲得腳本路由獲得路由后記該部分相關(guān)的源碼解析地址該文章講解了集群中關(guān)于路由規(guī)則實現(xiàn)的部分。 集群——router 目標(biāo):介紹dubbo中集群的路由,介紹dubbo-cluster下router包的源碼。 前言 路由規(guī)則 決定一次 dubbo 服務(wù)調(diào)用的目標(biāo)服務(wù)器,分為條件路由規(guī)則和腳本路...

    FullStackDeveloper 評論0 收藏0
  • dubbo源碼解析四十八)異步化改造

    摘要:大揭秘異步化改造目標(biāo)從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發(fā)送請求過程講到的十四的,在以前的邏輯會直接在方法中根據(jù)配置區(qū)分同步異步單向調(diào)用。改為關(guān)于可以參考源碼解析十遠(yuǎn)程通信層的六。 2.7大揭秘——異步化改造 目標(biāo):從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協(xié)議,關(guān)于協(xié)議的系列可以查看下面的文章: du...

    lijinke666 評論0 收藏0
  • dubbo源碼解析四十三)2.7新特性

    摘要:大揭秘目標(biāo)了解的新特性,以及版本升級的引導(dǎo)。四元數(shù)據(jù)改造我們知道以前的版本只有注冊中心,注冊中心的有數(shù)十個的鍵值對,包含了一個服務(wù)所有的元數(shù)據(jù)。 DUBBO——2.7大揭秘 目標(biāo):了解2.7的新特性,以及版本升級的引導(dǎo)。 前言 我們知道Dubbo在2011年開源,停止更新了一段時間。在2017 年 9 月 7 日,Dubbo 悄悄的在 GitHub 發(fā)布了 2.5.4 版本。隨后,版本...

    qqlcbb 評論0 收藏0
  • dubbo源碼解析四十七)服務(wù)端處理請求過程

    摘要:而存在的意義就是保證請求或響應(yīng)對象可在線程池中被解碼,解碼完成后,就會分發(fā)到的。 2.7大揭秘——服務(wù)端處理請求過程 目標(biāo):從源碼的角度分析服務(wù)端接收到請求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費端發(fā)送請求的過程,該篇就要將服務(wù)端處理請求的過程。也就是當(dāng)服務(wù)端收到請求數(shù)據(jù)包后的一系列處理以及如何返回最終結(jié)果。我們也知道消費端在發(fā)送請求的時候已經(jīng)做了編碼,所以我...

    yzzz 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<