1. 名词解释
本地存根
消费端实现一个装饰器类, 实现服务接口并持有服务接口的引用, 代理远程接口, 强化接口功能, 相当于Aop的around, 可以在真正调用远程接口前做参数校验, 后做结果缓存等额外的操作
一般我们系统中集成二方三方远程接口时, 都会对接口做一层封装, 以满足我们当前系统的规范, 通常这里都会做参数校验, 异常处理等操作, 和本地存根一致
本地伪装
消费端实现服务接口, 当消费端调用服务最终失败时, 在没有对服务调用使用 try-catch 包裹的情况下, 也能够返回一个预设默认值
2. 作用
典型的 RPC 调用客户端是依赖并且只依赖接口编程来进行远程调用的。在真正发起远程调用之前,用户往往需要做一些预处理的工作,比如提前校验参数。在拿到返回调用结果之后,用户可能需要缓存结果,或者是在调用失败的时候构造容错数据,而不是简单的抛出异常。
这个时候,用户可以编写出类似以下的代码来处理上面提出的这些场景:
try {
preProcess();
return service.invoke(...);
} catch (Throwable e) {
return mockValue;
} finally {
postProcess();
}
类似的,用户也可以通过面向切面编程 AOP 的高级技巧来解决上面的诉求,比如通过 Spring AOP 的方式可以通过类似下面的这段配置来完成。使用 AOP 的技巧相比上面的代码来说,避免了容错处理等与业务无关的代码对业务代码的侵入,使得业务处理主逻辑更简洁。
<bean id="demo-service-stub" class="org.apache.dubbo.demo.DemoServiceStub"/>
<bean id="demo-service-mock" class="org.apache.dubbo.demo.DemoServiceMock"/>
<aop:config>
<aop:aspect id="stub" ref="demo-service-stub">
<aop:pointcut id="stubPointcut" expression="execution(* org.apache.dubbo.samples.DemoService+.*(..))"/>
<aop:before method="preProcess" pointcut-ref="stubPointcut"/>
<aop:after-returning method="postProcess" pointcut-ref="stubPointcut"/>
</aop:aspect>
<aop:aspect id="mock" ref="demo-service-mock">
<aop:pointcut id="mockPointcut" expression="execution(* org.apache.dubbo.samples.DemoService+.*(..))"/>
<aop:after-throwing method="mock" pointcut-ref="mockPointcut"/>
</aop:aspect>
</aop:config>
为了进一步的方便用户做 Dubbo 开发,框架提出了本地存根 Stub 和本地伪装 Mock 的概念。通过约定大于配置的理念,进一步的简化了配置,使用起来更加方便,并且不依赖额外的 AOP 框架就达到了 AOP的效果。
- 本地存根的工作方式与 AOP 的
around advice
类似, - 而本地伪装的工作方式等同于 AOP 中的
after-throwing advice
,也就是说,只有当远程调用发生 exception 的时候才会执行本地伪装。
本地存根和本地伪装的工作流程如下图所示:
- 服务消费者发起调用
- 如果服务消费者端存在本地存根 Stub 的话,会先执行本地存根
- 本地存根 Stub 持有远程服务的 Proxy 对象,Stub 在执行的时候,会先执行自己的逻辑 (before),然后通过 Proxy 发起远程调用,最后在返回过程之前也会执行自己的逻辑 (after-returning)
- 如果远程服务的 Proxy 对象在执行过程中抛出了 exception,会执行服务消费端的本地伪装 Mock 的逻辑 (after-throwing),返回容错数据,从而达到服务降级的目的
3. 例子
详见《Dubbo 本地存根和本地伪装》
参考
Dubbo 本地存根和本地伪装
本地存根 官网 v2.7
本地伪装 官网 v2.7