Dubbo:本地存根

一、目标

二、原理

        远程服务后,客户端通常只剩下接口,而实现全在服务器端,但提供方有些时候想在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。通过代理类去完成这个调用,这样在 Stub类中,就可以做一些额外的事,来对服务的调用过程进行优化或者容错的处理。

在这里插入图片描述

三、示例

         参考官方示例

四、源码

        服务引用初始化时,进行本地伪装合法性校验。

org.apache.dubbo.config.AbstractInterfaceConfig#checkStubAndLocal代码片段
void checkStubAndLocal(Class<?> interfaceClass) {
    if (ConfigUtils.isNotEmpty(local)) {
        Class<?> localClass = ConfigUtils.isDefault(local) ?
                ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local);
        verify(interfaceClass, localClass);
    }
    if (ConfigUtils.isNotEmpty(stub)) {
    	//加载Stub类是否存在
        Class<?> localClass = ConfigUtils.isDefault(stub) ?
                ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub);
        //校验Stub类是否合法
        verify(interfaceClass, localClass);
    }
}

        创建服务引用代理。

org.apache.dubbo.config.ReferenceConfig#createProxy代码片段
private T createProxy(Map<String, String> map) {
	//忽略部分代码....
	
	//javaassist生成动态代理类
	return (T) PROXY_FACTORY.getProxy(invoker); 
}

        根据 Dubbo SPI 扩展机制,会先使用 ProxyFactory 的包装类,对 ProxyFactory 进行了功能增强,增强了本地存根功能,这类似与AOP。

org.apache.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper代码片段
public <T> T getProxy(Invoker<T> invoker) throws RpcException {
	//创建服务引用的目标代理
    T proxy = proxyFactory.getProxy(invoker);
    //判断是否泛型服务类型
    if (GenericService.class != invoker.getInterface()) {
        URL url = invoker.getUrl();
        String stub = url.getParameter(STUB_KEY, url.getParameter(LOCAL_KEY));
        if (ConfigUtils.isNotEmpty(stub)) {
            Class<?> serviceType = invoker.getInterface();
            if (ConfigUtils.isDefault(stub)) {
                if (url.hasParameter(STUB_KEY)) {
                    stub = serviceType.getName() + "Stub";
                } else {
                    stub = serviceType.getName() + "Local";
                }
            }
            try {
            	//加载、判断本地存根的类型是否存在
                Class<?> stubClass = ReflectUtils.forName(stub);
                if (!serviceType.isAssignableFrom(stubClass)) {
                    throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + serviceType.getName());
                }
                try {
                	//反射,目标代理作为构造参数,生成本地存根实例
                    Constructor<?> constructor = ReflectUtils.findConstructor(stubClass, serviceType);
                    proxy = (T) constructor.newInstance(new Object[]{proxy});
                    //export stub service
                    URLBuilder urlBuilder = URLBuilder.from(url);
                    if (url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT)) {
                        urlBuilder.addParameter(STUB_EVENT_METHODS_KEY, StringUtils.join(Wrapper.getWrapper(proxy.getClass()).getDeclaredMethodNames(), ","));
                        urlBuilder.addParameter(IS_SERVER_KEY, Boolean.FALSE.toString());
                        try {
                            export(proxy, (Class) invoker.getInterface(), urlBuilder.build());
                        } catch (Exception e) {
                            LOGGER.error("export a stub service error.", e);
                        }
                    }
                } catch (NoSuchMethodException e) {
                    throw new IllegalStateException("No such constructor \"public " + stubClass.getSimpleName() + "(" + serviceType.getName() + ")\" in stub implementation class " + stubClass.getName(), e);
                }
            } catch (Throwable t) {
                LOGGER.error("Failed to create stub implementation class " + stub + " in consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", cause: " + t.getMessage(), t);
                // ignore
            }
        }
    }
    return proxy;
}

引用

官方文档-本地存根

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值