本地伪装
功能描述
Dubbo3 中存在一种机制可以实现轻量级的服务降级,即本地伪装1。
使用场景
本地伪装通常用于服务降级。例如,对于一个验证服务,当所有服务提供者都挂掉时,如果服务消费者此时发起远程调用,则调用会失败并抛出 RpcException
异常。
为了避免直接抛出异常的这种情况,客户端可以使用本地伪装提供 Mock 数据并返回授权失败。
使用方法
启用 Mock 配置
在 Spring XML 配置文件中以以下方式配置
<dubbo:reference interface="com.foo.BarService" mock="true" />
或者
<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
在项目中提供 Mock 实现2
package com.foo;
public class BarServiceMock implements BarService {
public String sayHello(String name) {
// You can fake fault-tolerant data, this method is only executed when RpcException occurs
return "fault tolerance data";
}
}
使用 return 关键字模拟返回值
使用 return
返回一个由字符串表示的对象作为 Mock 的返回值。合法的字符串可以是
- empty: 代表空,返回基本类型的默认值,集合类的空值,自定义实体类的空对象3
- null: 返回
null
- true: 返回
true
- false: 返回
false
- JSON 字符串: 返回 JSON 字符串反序列化后得到的对象
例如,如果服务的消费者经常需要使用 try-catch 来捕获异常,例如
public class DemoService {
public Offer findOffer(String offerId) {
Offer offer = null;
try {
offer = offerService. findOffer(offerId);
} catch (RpcException e) {
logger. error(e);
}
return offer;
}
}
那么考虑改为 Mock 实现,并在 Mock 实现中 return null
。如果只是想简单地忽略异常,在 2.0.11
及以上版本中可以使用
<dubbo:reference interface="com.foo.BarService" mock="return null" />
使用 throw 关键字 Mock 抛出异常
使用 throw
返回一个 Exception 对象作为 Mock 的返回值。
调用失败时抛出默认的 RPCException
<dubbo:reference interface="com.foo.BarService" mock="throw"/>
调用发生错误时,抛出指定的 Exception4
<dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException"/>
使用 force 和 fail 关键字配置 Mock 的行为
force:
表示强制使用 Mock 行为,在这种情况下不会进行远程调用。
fail:
与默认行为一致,只有当远程调用发生错误时才会使用 Mock 行为。也就是说,在配置时实际上可以不使用 fail
关键字,而直接使用 throw
或 return
。
force:
和 fail:
都支持与 throw
或 return
结合使用。
强制返回指定的值
<dubbo:reference interface="com.foo.BarService" mock="force:return fake"/>
强制抛出指定的异常
<dubbo:reference interface="com.foo.BarService" mock="force:throw com.foo.MockException"/>
调用失败时返回指定的值
<dubbo:reference interface="com.foo.BarService" mock="fail:return fake"/>
<!-- Equivalent to the following writing -->
<dubbo:reference interface="com.foo.BarService" mock="return fake"/>
调用失败时抛出异常
<dubbo:reference interface="com.foo.BarService" mock="fail:throw com.foo.MockException"/>
<!-- Equivalent to the following writing -->
<dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException"/>
在方法级别配置 Mock
Mock 可以指定在方法级别,假设 com.foo.BarService
上有几个方法,我们可以分别为 sayHello()
方法指定 Mock 行为。
具体的配置如下。在这个例子中,无论何时调用 sayHello()
,它都会强制返回“fake”
<dubbo:reference id="demoService" check="false" interface="com.foo.BarService">
<dubbo:parameter key="sayHello.mock" value="force:return fake"/>
</dubbo:reference>
注意事项
Mock 是 Stub 的一个子集,它方便服务提供者在客户端实现容错逻辑。因为通常需要在 RpcException(例如网络故障、超时等)发生时执行容错,而业务异常(例如登录用户名和密码错误)则不需要容错。如果使用 Stub,则可能需要捕获并依赖 RpcException 类,但使用 Mock 则不需要依赖 RpcException,因为它的约定是在 RpcException 发生时才执行。 ↩︎
在接口旁边,放置一个实现 BarService 接口并具有无参数构造函数的 Mock 实现。同时,如果在配置文件中没有显式指定 Mock 类,那么需要确保 Mock 类的全限定类名是
原始全限定类名+Mock
的形式,例如com.foo.BarServiceMock
,否则 Mock 会失败。 ↩︎如果返回值是实体类,则会返回一个带有默认值的空对象,而不是
null
。 ↩︎自定义异常必须具有以
String
作为输入参数的构造函数,它将用于接收异常信息。 ↩︎