文章

集群容错(八)之Mock实现

集群容错(八)之Mock实现

本文基于 Dubbo 2.6.1 版本,望知悉。

1. 概述

本文接 《精尽 Dubbo 源码解析 —— 集群容错(七)之 Router 实现》 一文,分享 dubbo-cluster 模块, mock 包,实现 Dubbo 如下功能:

  • 本地伪装 :通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。
  • 服务降级 :可以通过服务降级功能,临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

老艿艿:如果不熟悉的胖友,推荐结合着 《Dubbo 用户指南 —— 本地伪装》《Dubbo 用户指南 —— 服务降级》 一起学习。

本文涉及类如下图:

Mock相关类图

Mock 相关类

  • 分成两个部分:
    • MockClusterWrapper + MockClusterInvoker + MockClusterSelector
    • MockProtocol + MockInvoker

2. MockClusterWrapper

com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper ,实现 Cluster 接口,Mock Cluster Wrapper 实现类。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MockClusterWrapper implements Cluster {
    /**
     * 真正的 Cluster 对象
     */
    private Cluster cluster;

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

    @Override
    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
        return new MockClusterInvoker<T>(directory, // <2>
                this.cluster.join(directory)); // <1>
    }
}

3. MockClusterInvoker

com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker ,实现 Invoker 接口,MockClusterWrapper 对应的 Invoker 实现类。

3.1 构造方法

1
2
3
4
5
6
7
8
9
10
private final Directory<T> directory;
/**
 * 真正的 Invoker 对象
 */
private final Invoker<T> invoker;

public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
    this.directory = directory;
    this.invoker = invoker;
}

3.2 invoke

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Override
public Result invoke(Invocation invocation) throws RpcException {
    Result result;
    // 获得 "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
        // 调用原 Invoker ,发起 RPC 调用
        result = this.invoker.invoke(invocation);
    //【第二种】强制服务降级 http://dubbo.apache.org/zh-cn/docs/user/demos/service-downgrade.html
    } 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);
    // 【第三种】失败服务降级 http://dubbo.apache.org/zh-cn/docs/user/demos/service-downgrade.html
    } else {
        // fail-mock
        try {
            // 调用原 Invoker ,发起 RPC 调用
            result = this.invoker.invoke(invocation);
        } catch (RpcException e) {
            // 业务性异常,直接抛出
            if (e.isBiz()) {
                throw e;
            } else {
                if (logger.isWarnEnabled()) {
                    logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                }
                // 失败后,调用 Mock Invoker ,执行本地 Mock 逻辑
                result = doMockInvoke(invocation, e);
            }
        }
    }
    return result;
}

  • 第 5 行:获得 三种 “mock” 配置项。根据不同的配置,分成 情况。
  • ========== 第一种:无 Mock

  • 第 10 行:只调用真正的即不进行 Mock 逻辑 invoker 的 #invoke(invocation) 方法,发起 RPC 调用, 。
  • ========== 第二种:强制服务降级

  • 第 12 行:开头强制《Dubbo 用户指南 —— 服务降级》 “mock” 配置项以 “force” , 服务降级,即 。
  • 第 18 行:直接Mock Invoker「3.3 doMockInvoke」 调用 #doMockInvoke(invocation, null) 方法,调用 ,执行本地 Mock 逻辑。详细解析,见 。
  • ========== 第三种:失败服务降级

  • 第 24 行:优先真正的即不进行 Mock 逻辑 ,调用 invoker 的 #invoke(invocation) 方法,发起 RPC 调用, 。
  • 第 25 至 36 行:处理 RpcException 异常。也仅仅处理这种类型的异常
    • 第 26 至 28 行:若发生业务性 异常,直接抛出异常。
    • 第 29 至 35 行:失败后Mock Invoker「3.3 doMockInvoke」 ,调用 #doMockInvoke(invocation, null) 方法,调用 ,执行本地 Mock 逻辑。详细解析,见 。

总的来说,MockClusterInvoker 的 #invoke(Invocation) 方法的过程,根据不同的 “mock” 配置,”组合”调用真正的Mock 的 Invoker 。

3.3 doMockInvoke

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private Result doMockInvoke(Invocation invocation, RpcException e) {
    Result result;
    // 第一步,获得 Mock Invoker 对象
    Invoker<T> mInvoker;
    // 路由匹配 Mock Invoker 集合
    List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
    // 如果不存在,创建 MockInvoker 对象
    if (mockInvokers == null || mockInvokers.isEmpty()) {
        mInvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
    // 如果存在,选择第一个
    } else {
        mInvoker = mockInvokers.get(0);
    }
    // 第二步,调用,执行本地 Mock 逻辑
    try {
        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;
}

  • 第 3 至 13 行:第一步MockInvoker ,获得 对象。
    • 第 6 行:调用 路由匹配「3.4 selectMockInvoker」 #selectMockInvoker(invocation) 方法, Mock Invoker 集合。详细解析,见 。
    • 第 7 至 9 行:若不创建 存在, MockInvoker 对象。
    • 第 10 至 13 行:若已选择 不能再, 第一个 Mock Invoker 对象。
  • 第 14 至 16 行:调用 MockInvoker#invoke(invocation) 方法,执行本地 Mock 逻辑。
  • 第 17 至 25 行:处理异常

3.4 selectMockInvoker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private List<Invoker<T>> selectMockInvoker(Invocation invocation) {
    List<Invoker<T>> invokers = null;
    if (invocation instanceof RpcInvocation) {
        // 存在隐含契约(虽然在接口声明中增加描述,但扩展性会存在问题.同时放在 attachment 中的做法需要改进
        ((RpcInvocation) invocation).setAttachment(Constants.INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
        // directory 根据 invocation 中 attachment 是否有 Constants.INVOCATION_NEED_MOCK,来判断获取的是 normal invokers or mock invokers
        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;
}

  • 第 5 行:设置 RpcInvocation 的 true “invocation.need.mock” 为 。
  • 第 8 行:调用 所有true「3.4.1 MockInvokersSelector」 Directory#list(invocation) 方法,获得 Invoker 集合。因为【第 5 行】设置了 “invocation.need.mock” 为 ,所以实际获得的是 MockInvoker 集合。详细解析,见 。

3.4.1 MockInvokersSelector

com.alibaba.dubbo.rpc.cluster.router.MockInvokersSelector ,实现 Router 接口,MockInvoker 路由选择器实现类。

因为 AbstractDirectory 的

#setRouters(List routers)

方法中,都会添加

MockInvokersSelector

,如下图所示:

setRouters方法示意图

setRouters

  • 所以,每次 Directory#list(invocation) 的过程中,都会执行 MockInvokersSelector 的路由逻辑。

#route(List invokers, URL url, Invocation invocation) 方法,根据 "invocation.need.mock" 路由匹配**对应类型**的 Invoker 集合:

  • 1、若为 trueMock , Invoker 集合。
  • 2、若为 false普通 , Invoker 集合。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public <T> List<Invoker<T>> route(final List<Invoker<T>> invokers, URL url, final Invocation invocation) throws RpcException {
    // 获得普通 Invoker 集合
    if (invocation.getAttachments() == null) {
        return getNormalInvokers(invokers);
    } else {
        // 获得 "invocation.need.mock" 配置项
        String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
        // 获得普通 Invoker 集合
        if (value == null) {
            return getNormalInvokers(invokers);
        // 获得 MockInvoker 集合
        } else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
            return getMockedInvokers(invokers);
        }
    }
    // 其它,不匹配,直接返回 `invokers` 集合
    return invokers;
}

  • 分成三种 情况,我们一个一个来看。在看具体情况之前,我们先来看 #hasMockProviders(invokers) 方法,判断是否有 MockInvoker 。代码如下:
1
2
3
4
5
6
7
8
9
10
private <T> boolean hasMockProviders(final List<Invoker<T>> invokers) {
    boolean hasMockProvider = false;
    for (Invoker<T> invoker : invokers) {
        if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) { // 协议为 "mock"
            hasMockProvider = true;
            break;
        }
    }
    return hasMockProvider;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- 通过 </font>protocol = "mock"</font> 来判断,是否为 </font>**Mock</font>**Invoker 。所以只要</font>**不为</font>** MockInvoker ,就是</font>**普通</font>** Invoker 。关于 </font>"mock"</font> 协议,我们稍后在 </font>[「4. MockProtocol」](http://svip.iocoder.cn/Dubbo/cluster-8-impl-mock/#) 中,详细解析。```

- 【第**一未设置普通**
种】第 3 至 5 行 || 第 9 至 11 行:若
"invocation.need.mock"
配置项,调用
#getNormalInvokers(invokers)
方法,获得
Invoker 集合。代码如下:

```java
private <T> List<Invoker<T>> getNormalInvokers(final List<Invoker<T>> invokers) {
    // 不包含 MockInvoker 的情况下,直接返回 `invokers` 集合
    if (!hasMockProviders(invokers)) {
        return invokers;
    } else {
        // 若包含 MockInvoker 的情况下,过滤掉 MockInvoker ,创建普通 Invoker 集合
        List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(invokers.size());
        for (Invoker<T> invoker : invokers) {
            if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
                sInvokers.add(invoker);
            }
        }
        return sInvokers;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- 第 2 至 4 行:调用 </font>#hasMockProviders(invokers)</font> 方法,判断</font>**不包含</font>** MockInvoker 的情况,直接返回 </font>invokers</font> 集合。- 第 6 至 13 行:若</font>**包含</font>** MockInvoker 的情况,</font>**过滤</font>**掉 MockInvoker ,创建</font>**普通</font>** Invoker 集合。```

- 【第**二trueMock**
种】第 12 至 15 行:若设置
"invocation.need.mock"
配置项为
,调用
#getMockedInvokers(invokers)
方法,获得
Invoker 集合。代码如下:

```java
private <T> List<Invoker<T>> getMockedInvokers(final List<Invoker<T>> invokers) {
    // 不包含 MockInvoker 的情况下,直接返回 null
    if (!hasMockProviders(invokers)) {
        return null;
    }
    // 过滤掉普通 Invoker ,创建 MockInvoker 集合
    List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(1); // 一般情况就一个,所以设置了默认数组大小为 1 。
    for (Invoker<T> invoker : invokers) {
        if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
            sInvokers.add(invoker);
        }
    }
    return sInvokers;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- 和 </font>#getNormalInvokers(invokers)</font> 方法,</font>**相反</font>**。比较易懂,胖友看代码注释。```

- 【第**三不匹配一**
种】第 18 行:其它,
,直接返回
invokers
集合。理论上,应该调用和【第
种】一样,调用
#getNormalInvokers(invokers)
方法。不过没关系, 从目前代码来看,这块是走不到的。

# 4. MockProtocol

com.alibaba.dubbo.rpc.support.MockProtocol ,实现 AbstractProtocol 抽象类,用于在服务**消费者**,通过类型为 "mock" 的 URL ,引用创建 MockInvoker 对象。代码如下:

```java
public final class MockProtocol extends AbstractProtocol {

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

    @Override
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        return new MockInvoker<T>(url);
    }

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

  • #export(Invoker)实现 方法,不允许调用,直接抛出 UnsupportedOperationException 异常。
  • #refer(Class type, Url)实现MockInvoker运维平台静态 方法,引用创建 对象。一般情况下,我们可以通过 dubbo-admin 或者直接向 Zookeeper 写入 URL ,例如:
1
2
3
4
// 实际写入的 URL
/dubbo/com.alibaba.dubbo.demo.DemoService/providers/mock%3A%2F%2F10.20.153.11%2Fcom.alibaba.dubbo.demo.DemoService%3Fdynamic%3Dtrue%26application%3Dfoo
// decode URL
/dubbo/com.alibaba.dubbo.demo.DemoService/providers/mock://10.20.153.11/com.alibaba.dubbo.demo.DemoService?dynamic=true&application=foo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- 为什么要是</font>**静态</font>** URL 呢?因为非静态 URL ,可能被注册中心删除。```

当然,我们在 [「3.3 doMockInvoke」](http://svip.iocoder.cn/Dubbo/cluster-8-impl-mock/#) 中也看到,即使不**手动**添加 "mock" URL ,在【第 9 行】代码中也会**自动**创建 MockInvoker 对象。

# 5. MockInvoker

com.alibaba.dubbo.rpc.support.MockInvoker ,实现 Invoker 接口,**Mock** Invoker 实现类。

## 5.1 构造方法

```java
/**
 * ProxyFactory$Adaptive 对象
 */
private final static ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
/**
 * mock 与 Invoker 对象的映射缓存
 *
 * @see #getInvoker(String)
 */
private final static Map<String, Invoker<?>> mocks = new ConcurrentHashMap<String, Invoker<?>>();
/**
 * mock 与 Throwable 对象的映射缓存
 *
 * @see #getThrowable(String)
 */
private final static Map<String, Throwable> throwables = new ConcurrentHashMap<String, Throwable>();

/**
 * URL 对象
 */
private final URL url;

public MockInvoker(URL url) {
    this.url = url;
}

5.2 invoke

#invoke(Invocation)实现方法,执行 Mock 逻辑。代码如下:

1
plain 1: @Override  2: public Result invoke(Invocation invocation) throws RpcException {  3:     if (invocation instanceof RpcInvocation) {  4:         ((RpcInvocation) invocation).setInvoker(this);  5:     }  6:     // 获得 `"mock"` 配置项,方法级 > 类级  7:     String mock = getUrl().getParameter(invocation.getMethodName() + "." + Constants.MOCK_KEY);  8:     if (StringUtils.isBlank(mock)) {  9:         mock = getUrl().getParameter(Constants.MOCK_KEY); 10:     } 11:     if (StringUtils.isBlank(mock)) { // 不允许为空 12:         throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url)); 13:     } 14:     // 标准化 `"mock"` 配置项 15:     mock = normalizedMock(URL.decode(mock)); 16:     // 等于 "return " ,返回值为空的 RpcResult 对象 17:     if (Constants.RETURN_PREFIX.trim().equalsIgnoreCase(mock.trim())) { 18:         RpcResult result = new RpcResult(); 19:         result.setValue(null); 20:         return result; 21:     // 以 "return " 开头,返回对应值的 RpcResult 对象 22:     } else if (mock.startsWith(Constants.RETURN_PREFIX)) { 23:         mock = mock.substring(Constants.RETURN_PREFIX.length()).trim(); 24:         mock = mock.replace('`', '"'); 25:         try { 26:             // 解析返回类型 27:             Type[] returnTypes = RpcUtils.getReturnTypes(invocation); 28:             // 解析返回值 29:             Object value = parseMockValue(mock, returnTypes); 30:             // 创建对应值的 RpcResult 对象,并返回 31:             return new RpcResult(value); 32:         } catch (Exception ew) { 33:             throw new RpcException("mock return invoke error. method :" + invocation.getMethodName() + ", mock:" + mock + ", url: " + url, ew); 34:         } 35:     // 以 "throw" 开头,抛出 RpcException 异常 36:     } else if (mock.startsWith(Constants.THROW_PREFIX)) { 37:         mock = mock.substring(Constants.THROW_PREFIX.length()).trim(); 38:         mock = mock.replace('`', '"'); 39:         if (StringUtils.isBlank(mock)) { // 禁止为空 40:             throw new RpcException(" mocked exception for Service degradation. "); 41:         } else { // user customized class 42:             // 创建自定义异常 43:             Throwable t = getThrowable(mock); 44:             // 抛出业务类型的 RpcException 异常 45:             throw new RpcException(RpcException.BIZ_EXCEPTION, t); 46:         } 47:     // 自定义 Mock 类,执行自定义逻辑 48:     } else { 49:         try { 50:             // 创建 Invoker 对象 51:             Invoker<T> invoker = getInvoker(mock); 52:             // 执行 Invoker 对象的调用逻辑 53:             return invoker.invoke(invocation); 54:         } catch (Throwable t) { 55:             throw new RpcException("Failed to create mock implemention class " + mock, t); 56:         } 57:     } 58: }

  • 第 6 至 13 行:获得 方法级类级 “mock” 配置项,优先从 的参数,再从 的参数。
  • 第 15 行:调用 「5.3 normalizedMock」 #normalizedMock(mock) 方法,标准化 “mock” 配置项。详细解析,见 。
  • 下面根据 三种 mock ,分成 情况。
  • 【第 1.1空 种】第 16 至 20 行:等于 “return” ,返回值为 的 RpcResult 对象。
  • 【第 1.2对应值 种】第 21 至 34 行:以 “return” 开头,返回 的 RpcResult 对象。
    • 第29 行:调用 返回值「5.4 parseMockValue」 #parseMockValue(mock, returnTypes) 方法,解析 。详细解析,见 。
  • 【第 2对应的 种】第 35 至 46 行:以 “throw” 开头,抛出 RpcException 异常。
    • 第 43 行:调用 自定义「5.5 getThrowable」 #getThrowable(mock) 对象,创建 异常。详细解析,见 。
  • 【第 3自定义 种】第 47 至 57 行: Mock 类,执行自定义逻辑。
    • 第 51 行:调用 「5.6 getInvoker」 #getInvoker(mock) 方法,获得 Invoker 对象。详细解析,见 。
    • 第 53 行:调用 自定义 Invoker#invoke(invocation) 方法,执行 Mock 逻辑。

5.3 normalizedMock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private String normalizedMock(String mock) {
    // 若为空,直接返回
    if (mock == null || mock.trim().length() == 0) {
        return mock;
    // 若果为 "true" "default" "fail" "force" 四种字符串,修改为对应接口 + "Mock" 类
    } else if (ConfigUtils.isDefault(mock) || "fail".equalsIgnoreCase(mock.trim()) || "force".equalsIgnoreCase(mock.trim())) {
        mock = url.getServiceInterface() + "Mock";
    }
    // 若以 "fail:" 开头,去掉该开头
    if (mock.startsWith(Constants.FAIL_PREFIX)) {
        mock = mock.substring(Constants.FAIL_PREFIX.length()).trim();
    // 若以 "force:" 开头,去掉该开头
    } else if (mock.startsWith(Constants.FORCE_PREFIX)) {
        mock = mock.substring(Constants.FORCE_PREFIX.length()).trim();
    }
    return mock;
}

  • 【第一空 种】第 2 至 4 行:若为 ,直接返回。
  • 【第二truedefaultfailforce 种】第 5 至 8 行:若为 ,修改为对应接口 + “Mock” 。
  • 【第三开头开头强制失败 种】第 9 至 15 行:若以 “fail:” 或 “force:” ,去掉 。该开头,仅用于 MockClusterInvoker 表示 Mock 还是 Mock 。

5.4 parseMockValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public static Object parseMockValue(String mock) {
    return parseMockValue(mock, null);
}

public static Object parseMockValue(String mock, Type[] returnTypes) {
    // 解析值(不考虑返回类型)
    Object value;
    if ("empty".equals(mock)) { // 未赋值的对象,即 new XXX() 对象
        value = ReflectUtils.getEmptyObject(returnTypes != null && returnTypes.length > 0 ? (Class<?>) returnTypes[0] : null);
    } else if ("null".equals(mock)) { // null
        value = null;
    } else if ("true".equals(mock)) { // true
        value = true;
    } else if ("false".equals(mock)) { // 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("[")) { // List
        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;
}

  • 解析值转换类型 ,并 成对应的返回 。

5.5 getThrowable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Throwable getThrowable(String throwStr) {
    // 从缓存中,获得 Throwable 对象
    Throwable throwable = throwables.get(throwStr);
    if (throwable != null) {
        return throwable;
    }
    // 不存在,创建 Throwable 对象
    Throwable t;
    try {
        // 获得异常类
        Class<?> bizException = ReflectUtils.forName(throwStr);
        // 获得构造方法
        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);
        }
    } catch (Exception e) {
        throw new RpcException("mock throw error :" + throwStr + " argument error.", e);
    }
    return t;
}

  • 代码比较易懂,胖友看代码注释。

5.6 getInvoker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private Invoker<T> getInvoker(String mockService) {
    // 从缓存中,获得 Invoker 对象
    Invoker<T> invoker = (Invoker<T>) mocks.get(mockService);
    if (invoker != null) {
        return invoker;
    }
    // 不存在,创建 Invoker 对象
    // 1. 获得接口类
    Class<T> serviceType = (Class<T>) ReflectUtils.forName(url.getServiceInterface());
    // 2. 若为 `true` `default` ,修改修改为对应接口 + "Mock" 类。这种情况出现在原始 `mock = fail:true` 或 `mock = force:true` 等情况
    if (ConfigUtils.isDefault(mockService)) {
        mockService = serviceType.getName() + "Mock";
    }
    // 3. 获得 Mock 类
    Class<?> mockClass = ReflectUtils.forName(mockService);
    // 4. 校验 Mock 类,实现了接口类
    if (!serviceType.isAssignableFrom(mockClass)) {
        throw new IllegalArgumentException("The mock implemention class " + mockClass.getName() + " not implement interface " + serviceType.getName());
    }
    try {
        // 5. 创建 Mock 对象
        T mockObject = (T) mockClass.newInstance();
        // 6. 创建 Mock 对应,对应的 Invoker 对象
        invoker = proxyFactory.getInvoker(mockObject, serviceType, url);
        // 7. 添加到缓存
        if (mocks.size() < 10000) {
            mocks.put(mockService, invoker);
        }
        return invoker;
    } catch (InstantiationException e) {
        throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implemention class " + mockClass.getName(), e);
    } catch (IllegalAccessException e) {
        throw new IllegalStateException(e);
    }
}

  • 代码比较易懂,胖友看代码注释。

6. AbstractInterfaceConfig

#checkStubAndMock(Class<?> interfaceClass) 方法,校验 Stub 和 Mock 相关的配置。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected void checkStubAndMock(Class<?> interfaceClass) {
    // 【省略代码】`local` 配置项的校验,和 `stub` 一样。
    // 【省略代码】`stub` 配置项的校验

    // mock 配置校验
    if (ConfigUtils.isNotEmpty(mock)) {
        if (mock.startsWith(Constants.RETURN_PREFIX)) { // 处理 "return " 开头的情况
            String value = mock.substring(Constants.RETURN_PREFIX.length());
            // 校验 Mock 值,配置正确
            try {
                MockInvoker.parseMockValue(value);
            } catch (Exception e) {
                throw new IllegalStateException("Illegal mock json value in <dubbo:service ... mock=\"" + mock + "\" />");
            }
        } else {
            // 获得 Mock 类
            Class<?> mockClass = ConfigUtils.isDefault(mock) ? ReflectUtils.forName(interfaceClass.getName() + "Mock") : ReflectUtils.forName(mock);
            // 校验是否实现接口类
            if (!interfaceClass.isAssignableFrom(mockClass)) {
                throw new IllegalStateException("The mock implementation class " + mockClass.getName() + " not implement interface " + interfaceClass.getName());
            }
            // 校验是否有默认构造方法
            try {
                mockClass.getConstructor();
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("No such empty constructor \"public " + mockClass.getSimpleName() + "()\" in mock implementation class " + mockClass.getName());
            }
        }
    }
}

  • 代码比较易懂,胖友看代码注释。
  • 从 Mock 配置校验的逻辑我们可以看出,不允许配置 不能通过配置规则服务降级《Dubbo 用户指南 —— 服务降级》 “force:” 和 “fail:” 为开头。 所以, Java API 或者 XML ,又或者注解来配置 Mock 规则,只能通过 来开启 。具体的配置方式,参见 。
    • 同样,也不允许配置 “throws” 开头。
本文由作者按照 CC BY 4.0 进行授权