摘要:源碼分析一創(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ù),并定義降級后的返回策略。
源碼分析 (一)MockClusterWrapperpublic class MockClusterWrapper implements Cluster { private Cluster cluster; public MockClusterWrapper(Cluster cluster) { this.cluster = cluster; } @Override publicInvoker 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 Directory2.invokedirectory; /** * invoker對象 */ private final Invoker invoker;
@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; Invokerminvoker; // 路由匹配 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.selectMockInvokerprivate 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 publicList > 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.getMockedInvokersprivateList > 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.getNormalInvokersprivateList > 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.hasMockProvidersprivateboolean 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(五)MockInvokerExporter 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); } }
本地偽裝的invoker實現(xiàn)類。
1.屬性/** * 代理工廠 */ private final static ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); /** * mock 與 Invoker 對象的映射緩存 */ private final static Map2.parseMockValue> mocks = new ConcurrentHashMap >(); /** * 異常集合 */ private final static Map throwables = new ConcurrentHashMap (); /** * url對象 */ private final URL url;
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 Invokerinvoker = 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.normalizedMockpublic 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.getThrowablepublic 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.getInvokerprivate InvokergetInvoker(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.getMockObjectpublic 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
摘要:可以參考源碼解析二十四遠(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)方法。...
摘要:源碼分析一創(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ī)則和腳本路...
摘要:大揭秘異步化改造目標(biāo)從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發(fā)送請求過程講到的十四的,在以前的邏輯會直接在方法中根據(jù)配置區(qū)分同步異步單向調(diào)用。改為關(guān)于可以參考源碼解析十遠(yuǎn)程通信層的六。 2.7大揭秘——異步化改造 目標(biāo):從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協(xié)議,關(guān)于協(xié)議的系列可以查看下面的文章: du...
摘要:大揭秘目標(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 版本。隨后,版本...
摘要:而存在的意義就是保證請求或響應(yīng)對象可在線程池中被解碼,解碼完成后,就會分發(fā)到的。 2.7大揭秘——服務(wù)端處理請求過程 目標(biāo):從源碼的角度分析服務(wù)端接收到請求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費端發(fā)送請求的過程,該篇就要將服務(wù)端處理請求的過程。也就是當(dāng)服務(wù)端收到請求數(shù)據(jù)包后的一系列處理以及如何返回最終結(jié)果。我們也知道消費端在發(fā)送請求的時候已經(jīng)做了編碼,所以我...
閱讀 3237·2021-09-07 10:10
閱讀 3582·2019-08-30 15:44
閱讀 2582·2019-08-30 15:44
閱讀 2997·2019-08-29 15:11
閱讀 2225·2019-08-28 18:26
閱讀 2748·2019-08-26 12:21
閱讀 1116·2019-08-23 16:12
閱讀 3027·2019-08-23 14:57