摘要:源碼分析一創建該類是服務降級的裝飾器類,對進行了功能增強,增強了服務降級的功能。注意隱式契約盡管描述被添加到接口聲明中,但是可擴展性是一個問題。獲得服務類型獲得創建加入集合該方法是獲得。
集群——Mock
目標:介紹dubbo中集群的Mock,介紹dubbo-cluster下關于服務降級和本地偽裝的源碼。前言
本文講解兩塊內容,分別是本地偽裝和服務降級,本地偽裝通常用于服務降級,比如某驗權服務,當服務提供方全部掛掉后,客戶端不拋出異常,而是通過 Mock 數據返回授權失敗。而服務降級則是臨時屏蔽某個出錯的非關鍵服務,并定義降級后的返回策略。
源碼分析 (一)MockClusterWrapperpublic class MockClusterWrapper implements Cluster { private Cluster cluster; public MockClusterWrapper(Cluster cluster) { this.cluster = cluster; } @Override publicInvoker join(Directory directory) throws RpcException { // 創建MockClusterInvoker return new MockClusterInvoker (directory, this.cluster.join(directory)); } }
該類是服務降級的裝飾器類,對Cluster進行了功能增強,增強了服務降級的功能。
(二)MockClusterInvoker該類是服務降級中定義降級后的返回策略的實現。
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 // 直接調用 result = this.invoker.invoke(invocation); // 如果強制服務降級 } else if (value.startsWith("force")) { if (logger.isWarnEnabled()) { logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl()); } //force:direct mock // 直接調用 Mock Invoker ,執行本地 Mock 邏輯 result = doMockInvoke(invocation, null); } else { //fail-mock // 失敗服務降級 try { // 否則正常調用 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); } // 如果調用失敗,則服務降級 result = doMockInvoke(invocation, e); } } } return result; }
該方法是定義降級后的返回策略的實現,根據配置的不同來決定不用降級還是強制服務降級還是失敗后再服務降級。
3.doMockInvoke@SuppressWarnings({"unchecked", "rawtypes"}) private Result doMockInvoke(Invocation invocation, RpcException e) { Result result = null; Invokerminvoker; // 路由匹配 Mock Invoker 集合 List > mockInvokers = selectMockInvoker(invocation); // 如果mockInvokers為空,則創建一個MockInvoker if (mockInvokers == null || mockInvokers.isEmpty()) { // 創建一個MockInvoker minvoker = (Invoker ) new MockInvoker(directory.getUrl()); } else { // 取出第一個 minvoker = mockInvokers.get(0); } try { // 調用invoke result = minvoker.invoke(invocation); } catch (RpcException me) { // 如果拋出異常,則返回異常結果 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; }
該方法是執行本地Mock,服務降級。
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) // 注意隱式契約(盡管描述被添加到接口聲明中,但是可擴展性是一個問題。附件中的做法需要改進) ((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. // 如果調用中存在Constants.INVOCATION_NEED_MOCK,則目錄將返回正常調用者列表,否則,將返回模擬調用者列表。 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該類是路由選擇器實現類。
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; }
該方法是根據配置來決定選擇普通的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。
以上三個類是對服務降級功能的實現,下面兩個類是對本地偽裝的實現。
(四)MockProtocol該類實現了AbstractProtocol接口,是服務
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 { // 創建MockInvoker return new MockInvoker (url); } }
本地偽裝的invoker實現類。
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)) { // 是數字 value = JSON.parse(mock); } else if (mock.startsWith("{")) { // 是map類型的 value = JSON.parseObject(mock, Map.class); } else if (mock.startsWith("[")) { // 是數組類型 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)); } // 標準化 `"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)) { // 根據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 // 創建自定義異常 Throwable t = getThrowable(mock); // 拋出業務類型的 RpcException 異常 throw new RpcException(RpcException.BIZ_EXCEPTION, t); } } else { //impl mock try { // 否則直接獲得invoker Invokerinvoker = getInvoker(mock); // 調用 return invoker.invoke(invocation); } catch (Throwable t) { throw new RpcException("Failed to create mock implementation class " + mock, t); } } }
該方法是本地偽裝的核心實現,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; }
該方法是規范化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; // 獲得構造方法 constructor = ReflectUtils.findConstructor(bizException, String.class); // 創建 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; } // 獲得服務類型 Class serviceType = (Class ) ReflectUtils.forName(url.getServiceInterface()); // 獲得MockObject T mockObject = (T) getMockObject(mockService, serviceType); // 創建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對象。
后記該部分相關的源碼解析地址:https://github.com/CrazyHZM/i...
該文章講解了集群中關于mock實現的部分,到這里為止,集群部分就全部講完了,這是2.6.x版本的集群,那在2.7中對于路由和配置規則都有相應的大改動,我會在之后2.7版本的講解中講到。接下來我將開始對序列化模塊進行講解。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/73265.html
摘要:可以參考源碼解析二十四遠程調用協議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠程通信層的四。二十的可以參考源碼解析十七遠程通信的一。 2.7大揭秘——消費端發送請求過程 目標:從源碼的角度分析一個服務方法調用經歷怎么樣的磨難以后到達服務端。 前言 前一篇文章講到的是引用服務的過程,引用服務無非就是創建出一個代理。供消費者調用服務的相關方法。...
摘要:源碼分析一創建一個該類是基于條件表達式規則路由工廠類。路由工廠獲得配置項,默認為獲得獲得類型讀取規則獲得腳本路由獲得路由后記該部分相關的源碼解析地址該文章講解了集群中關于路由規則實現的部分。 集群——router 目標:介紹dubbo中集群的路由,介紹dubbo-cluster下router包的源碼。 前言 路由規則 決定一次 dubbo 服務調用的目標服務器,分為條件路由規則和腳本路...
摘要:大揭秘異步化改造目標從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發送請求過程講到的十四的,在以前的邏輯會直接在方法中根據配置區分同步異步單向調用。改為關于可以參考源碼解析十遠程通信層的六。 2.7大揭秘——異步化改造 目標:從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協議,關于協議的系列可以查看下面的文章: du...
摘要:大揭秘目標了解的新特性,以及版本升級的引導。四元數據改造我們知道以前的版本只有注冊中心,注冊中心的有數十個的鍵值對,包含了一個服務所有的元數據。 DUBBO——2.7大揭秘 目標:了解2.7的新特性,以及版本升級的引導。 前言 我們知道Dubbo在2011年開源,停止更新了一段時間。在2017 年 9 月 7 日,Dubbo 悄悄的在 GitHub 發布了 2.5.4 版本。隨后,版本...
摘要:而存在的意義就是保證請求或響應對象可在線程池中被解碼,解碼完成后,就會分發到的。 2.7大揭秘——服務端處理請求過程 目標:從源碼的角度分析服務端接收到請求后的一系列操作,最終把客戶端需要的值返回。 前言 上一篇講到了消費端發送請求的過程,該篇就要將服務端處理請求的過程。也就是當服務端收到請求數據包后的一系列處理以及如何返回最終結果。我們也知道消費端在發送請求的時候已經做了編碼,所以我...
閱讀 3240·2021-09-07 10:10
閱讀 3584·2019-08-30 15:44
閱讀 2585·2019-08-30 15:44
閱讀 3003·2019-08-29 15:11
閱讀 2229·2019-08-28 18:26
閱讀 2750·2019-08-26 12:21
閱讀 1119·2019-08-23 16:12
閱讀 3034·2019-08-23 14:57