美文网首页dubbo
【Dubbo】 服务暴露

【Dubbo】 服务暴露

作者: 程序员驿站 | 来源:发表于2017-12-18 19:39 被阅读23次

问题

  1. dubbo的服务提供者是怎么将服务暴露给注册中心(这里是说zk)
  2. 消费者是怎么从zk获取服务的地址,进行调用的

时序图

未命名文件.png image.png

服务发布种类

本地发布

定义:本地发布是部署在jvm中, 在同一个服务,自己调用自己的接口没必要使用网络来通信

远程发布

暴露服务

(1) 只暴露服务端口:

  • 在没有注册中心,直接暴露提供者的情况下,即:
    • <dubbo:service regisrty="N/A" /> or <dubbo:registry address="N/A" />
  • ServiceConfig解析出的URL的格式为:
  • 基于扩展点的Adaptive机制,通过URL的"dubbo://"协议头识别,直接调用DubboProtocol的export()方法,打开服务端口。

(2) 向注册中心暴露服务:

暴露服务源码流程

2、ServiceBean实现了下面的接口
InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware

在spring容器启动的时候执行
实现了InitializingBean接口的afterPropertiesSet(),该接口为spring留给开发者的一个hook,系统启动只执行一次

afterPropertiesSet()里面主要干了什么事情呢
构建ProviderConfig 信息(如果集成了spring,这个是在DubboNamespaceHandler初始化的)
构建ApplicationConfig
构建ModuleConfig
构建RegistryConfig
构建MonitorConfig
构建ProtocolConfig

执行ServiceConfig的export()

public synchronized void export() {
        if (provider != null) {
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {
                delay = provider.getDelay();
            }
        }
        // 如果不需要暴露该服务,则就此结束
        if (export != null && ! export.booleanValue()) {
            return;
        }
        // 如果明确指定了想要延迟的时间差,则依赖线程休眠来完成延迟暴露,delay的值只有为-1或null才依赖spring的事件机制完成延迟暴露
        if (delay != null && delay > 0) {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep(delay);
                    } catch (Throwable e) {
                    }
                    doExport();
                }
            });
            thread.setDaemon(true);
            thread.setName("DelayExportServiceThread");
            thread.start();
        } else {
        // 重点在这里
            doExport();
        }
    }

private transient volatile boolean exported;

protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        //如果发布了就不执行
        if (exported) {
            return;
        }
        // 设置暴露状态
        exported = true;
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
        }
        checkDefault();
        if (provider != null) {
            if (application == null) {
                application = provider.getApplication();
            }
            if (module == null) {
                module = provider.getModule();
            }
            if (registries == null) {
                registries = provider.getRegistries();
            }
            if (monitor == null) {
                monitor = provider.getMonitor();
            }
            if (protocols == null) {
                protocols = provider.getProtocols();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            generic = true;
        } else {
            try {
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            checkInterfaceAndMethods(interfaceClass, methods);
            checkRef();
            generic = false;
        }
        if(local !=null){
            if(local=="true"){
                local=interfaceName+"Local";
            }
            Class<?> localClass;
            try {
                localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if(!interfaceClass.isAssignableFrom(localClass)){
                throw new IllegalStateException("The local implemention class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
        if(stub !=null){
            if(stub=="true"){
                stub=interfaceName+"Stub";
            }
            Class<?> stubClass;
            try {
                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if(!interfaceClass.isAssignableFrom(stubClass)){
                throw new IllegalStateException("The stub implemention class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
        checkApplication();
        checkRegistry();
        checkProtocol();
        this.parameters = fixApplicationParams(this.parameters);
        appendProperties(this);
        checkStubAndMock(interfaceClass);
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
        doExportUrls();
    }
private void doExportUrls() {
  // 解析所有的注册中心地址
    List<URL> registryURLs = loadRegistries(true);  
    for (ProtocolConfig protocolConfig : protocols) {
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}

调用者如何调用服务

引用服务

(1) 直连引用服务:

  • 在没有注册中心,直连提供者的情况下,即:
    • <dubbo:reference url="dubbo://service-host/com.foo.FooService?version=1.0.0" />
  • ReferenceConfig解析出的URL的格式为:
  • 基于扩展点的Adaptive机制,通过URL的"dubbo://"协议头识别,直接调用DubboProtocol的refer()方法,返回提供者引用。

(2) 从注册中心发现引用服务:

拦截服务

  • 基于扩展点的Wrapper机制,所有的Protocol扩展点都会自动套上Wrapper类。
  • 基于ProtocolFilterWrapper类,将所有Filter组装成链,在链的最后一节调用真实的引用。
  • 基于ProtocolListenerWrapper类,将所有InvokerListener和ExporterListener组装集合,在暴露和引用前后,进行回调。
  • 包括监控在内,所有附加功能,全部通过Filter拦截实现。

相关文章

网友评论

    本文标题:【Dubbo】 服务暴露

    本文链接:https://www.haomeiwen.com/subject/oxzmwxtx.html