dubbo源码分析第六篇一服务暴露第二小节一Invoker构建与exportor暴露

ServiceBean对象暴露服务

  • 服务暴露一般包括本地暴露和远程暴露
  • 本地暴露的协议为injvm,远程暴露的协议为registry+dubbo对应的协议类分别为InjvmProtocol和RegistryProtocol+DubboProtocol
  • Protocol$Adaptive进行export时,根据URL上的protocol值取协议实现类,如果无该参数则默认dubbo
本地暴露 URL为injvm协议远程暴露url协议一dubbo协议远程暴露ur协议二registry协议
injvm://127.0.0.1/com.renxl.demo.UserService?anyhost=true&application=dubbo-demo&…dubbo://192.168.2.103:19012/com.renxl.demo.UserService?anyhost=true&…registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?..
String scope = url.getParameter(SCOPE_KEY);
SCOPE_NONE是字符串“none”,一般这里为空
if (!SCOPE_NONE.equalsIgnoreCase(scope)) {
    step-1: 进行本地暴露
    if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
        exportLocal(url);
    }
    
    if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
        进行注册中心暴露
        if (CollectionUtils.isNotEmpty(registryURLs)) {
            for (URL registryURL : registryURLs) {
                ...... 删除其他代码
                url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY));
                URL monitorUrl = loadMonitor(registryURL);
                if (monitorUrl != null) {
                    url = url.addParameterAndEncoded(MONITOR_KEY, monitorUrl.toFullString());
                }
               
                String proxy = url.getParameter(PROXY_KEY);
                if (StringUtils.isNotEmpty(proxy)) {
                    registryURL = registryURL.addParameter(PROXY_KEY, proxy);
                }
                step-2: 构建Invoker
                registryURL为远程暴露协议二
				url为远程暴露协议一
                Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
                DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                step-3: 远程服务暴露
                Exporter<?> exporter = protocol.export(wrapperInvoker);
                exporters.add(exporter);
            }
        } 
        ...... 删除无注册中心情况
            
        
    }
}

injvm协议

	- 构建的url采用injvm协议 
	- 构建Invoker并暴露到exportermap
	- 加入exporters用于管控销毁
 private void exportLocal(URL url) {
 		url如下:
 		injvm://127.0.0.1/com.renxl.demo.UserService?anyhost=true&application=dubbo-demo&......
        URL local = URLBuilder.from(url)
        		采用injvm协议
                .setProtocol(LOCAL_PROTOCOL)
                .setHost(LOCALHOST_VALUE)
                .setPort(0)
                .build();
        Exporter<?> exporter = protocol.export(
                PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
        加入servicebean的exporters,一般包括本地和远程
        exporters.add(exporter);
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local);
    }

Invoker构建

  • 创建Invoker对象,用于内部方法调用
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
    
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
				根据参数调用目标对象目标方法
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

exportor暴露

  • 结合扩展点以及前文知道
  • 这里为Protocol A d a p t i v e − > P r o t o c o l F i l t e r W r a p p e r − > P r o t o c o l L i s t e n e r W r a p p e r − > I n j v m P r o t o c o l ; P r o t o c o l Adaptive ->ProtocolFilterWrapper->ProtocolListenerWrapper->InjvmProtocol; Protocol Adaptive>ProtocolFilterWrapper>ProtocolListenerWrapper>InjvmProtocol;ProtocolAdaptive获取InjvmProtocol对象,由于spi机制存在wrapper能力,所以InjvmProtocol被ProtocolListenerWrapper和ProtocolFilterWrapper包装
protocol.export(
                PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, local));
  • ProtocolListenerWrapper主要是构建根据url上exporter.listener构建监听器,监听服务unexport事件
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return new ListenerExporterWrapper<T>(protocol.export(invoker),
                Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                        .getActivateExtension(invoker.getUrl(), EXPORTER_LISTENER_KEY)));
    }
  • ProtocolFilterWrapper主要是构建dubbofilter链
   public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
   		忽略register协议
        if (REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        构建filter链
        return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER));
    }
  • injvmProtocol暴露的本质就是构建持有Invoker的Exporter对象,并加入exporterMap
  • exporterMap在将来发生通信,就是根据相应参数从exporterMap找对应的exporter,在获取其内部的Invoker进行方法调用
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
    }

远程暴露

  • 构建Invoker url为register协议
  • 暴露链路如下,具体实现参见第七小节

Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => RegistryProtocol

RegistryProtocol又会拿url参数对应的dubbo协议在进行一次暴露
Protocol$Adaptive => ProtocolFilterWrapper => ProtocolListenerWrapper => DubboProtocol

registryURL如下: registry://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?..
url如下: dubbo://192.168.2.103:19012/com.renxl.demo.UserService?anyhost=true&......

同injvm创建Invoker,不同的是协议registryURL为register:// 而url.toFullString()作为一个参数加入不同的是协议registryURL
url参数是一个dubbo协议,RegisterProtocol会通过这个url调用DubboProtocol
也就是说protocol.export(wrapperInvoker)先调用RegisterProtocol进行暴露

Invoker<?> invoker = PROXY_FACTORY.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);

总结

  • SPI的应用: Protocol$Adaptive根据url上protocol获取对应实现类进行服务暴露
  • SPI的应用: Protocol$Adaptive获取具体协议进行暴露,都会调用Wrapper完成监听,过滤等功能(内部判断如果是register协议则忽略)
  • 服务的暴露一般分远程和本地,暴露完毕添加到exporterMap,用于将来服务调用时进行查找
  • exporterMap的key,如果是本地为接口名,远程为接口名加端口号
本地远程
com.renxl.demol.UserServicecom.renxl.demol.UserService:19283

扩展点

Protocol$Adaptive 源码

  • 自适应协议扩展类进行export时,根据URL上的protocol值取协议实现类,如果无该参数则默认dubbo
public class Protocol$Adaptive implements Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public Exporter export(Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    public Invoker refer(Class arg0, URL arg1) throws RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        Protocol extension = (Protocol) ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
}



ProxyFactory$Adaptive源码

ProxyFactory$Adaptive 默认取javassist


public class ProxyFactory$Adaptive implements  ProxyFactory {
    public Object getProxy( Invoker arg0) throws RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        URL url = arg0.getUrl();
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
        ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
        return extension.getProxy(arg0);
    }

    public Object getProxy(Invoker arg0, boolean arg1) throws RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        URL url = arg0.getUrl();
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
        ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
        return extension.getProxy(arg0, arg1);
    }

    public Invoker getInvoker(Object arg0, java.lang.Class arg1, URL arg2) throws org.apache.dubbo.rpc.RpcException {
        if (arg2 == null) throw new IllegalArgumentException("url == null");
        URL url = arg2;
        String extName = url.getParameter("proxy", "javassist");
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.ProxyFactory) name from url (" + url.toString() + ") use keys([proxy])");
        ProxyFactory extension = (ProxyFactory) ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension(extName);
        return extension.getInvoker(arg0, arg1, arg2);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值