Dubbo-服务导出、暴露实现原理

文章目录

    • 入口之Spring与Dubbo集成
      • XML配置
      • XML配置解析
      • ServiceBean与Spring的整合
    • 服务暴露
      • 配置检查
      • 多协议服务暴露
        • 注册中心地址获取
        • URL信息组装
        • 本地导出
        • Filter责任链
        • 多注册中心远程导出
      • NettyServer 创建
        • ExchangeServer
        • Transporter
        • NettyServer

入口之Spring与Dubbo集成

XML配置

先看一段XML下的Dubbo服务配置

<!-- 指定dubbo项目名称 -->
<dubbo:application name="application_provider" />
<!-- 使用zookeeper做注册中心暴露服务地址 -->
 <dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 声明需要暴露的服务接口 ref指向接口实现类 首字母小写 -->
<dubbo:service interface="com.dubbo.demo.Provider"
                   ref="demoService" />

其他标签的配置说明,具体参考官网SCHEMA配置参考手册

XML配置解析

Dubbo这种标签定义Bean的方法,实际上是有一套自己的配置文件标签规范,Spring也允许开发者定义自己的XML SCHEMA,只是Spring有如下约定

  1. 自定义的标签模板XSD文件,需要在META-INF/spring.schemas中指定,dubbo中的配置文件XML模板为dubbo.xsd文件,有兴趣的可以去看看xsd文件规范,这里不展开说明。配置文件有了,还得有一个类来解析配置文件。
    Dubbo-服务导出、暴露实现原理_第1张图片
  2. 自定义的XSD文件解析类,需要在META-INF/spring.handlers中指定xsd文件的解析类,dubbo中指定解析类如下,DubboNamespaceHandler即为Dubbo配置文件的解析类
    Dubbo-服务导出、暴露实现原理_第2张图片
    看下DubboNamespaceHandler的实现,可以看到针对不同的配置标签有不同的解析
    Dubbo-服务导出、暴露实现原理_第3张图片

本文重点是服务暴露,因此重点关注service标签的解析,可以看到其XML中的Service最终会转化为一个ServiceBean

registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));

ServiceBean也是分析Dubbo服务导出的入口

ServiceBean与Spring的整合

Dubbo的启动依赖于Spring的启动,Dubbo服务在接收到Spring容器的刷新事件后,会执行服务暴露、导出工作,看下ServiceBean是如何与Spring整合在一起的。

看下ServiceBean的类定义

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {
	//省略其他变量、方法
	private static transient ApplicationContext SPRING_CONTEXT;
	private transient String beanName;
	@Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }
}

明确如下几点

  1. ServiceBean继承自ServiceConfig,因此ServiceBean中保留有Dubbo服务相关的配置,如导出的接口interfaceName、要导出的方法methods
  2. ServiceBean实现了ApplicationContextAwareBeanNameAware接口,因此能获取到Spring的上下文对象ApplicationContext以及bean的beanName。如图所示
    Dubbo-服务导出、暴露实现原理_第4张图片
  3. 实现了InitializingBean, DisposableBean因此能在Dubbo服务对应的bean初始化完成时执行延迟导出工作,!isDelay() 标识延迟导出,即delay>0时,isDelay返回false,在afterPropertiesSet方法中进行服务导出,表示延迟到Spring容器初始化完成时暴露服务
    Dubbo-服务导出、暴露实现原理_第5张图片
  4. 实现了ApplicationListener,使得ServiceBean能够接收到Spring容器的刷新事件,在监听到刷新事件时进行服务导出
    Dubbo-服务导出、暴露实现原理_第6张图片

至此已经清晰了服务导出的入口实在ServiceBean的export方法中

服务暴露

在从代码层面上分析服务暴露过程之前,先上一张Dubbo官方的暴露服务时序图,大家后面好对照着时序图来跟踪、分析源码
Dubbo-服务导出、暴露实现原理_第7张图片

先看下ServiceBean#export方法的实现,逻辑简单,分为三步

  1. 从ProviderConfig中获取export属性、delay属性
  2. 如果export=false,表示不需要导出,直接return
  3. 如果配置了延迟导出(delay>0),利用ScheduledExecutorService进行延迟导出
private ProviderConfig provider;

private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));

public synchronized void export() {
        if (provider != null) {
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {
                delay = provider.getDelay();
            }
        }
        if (export != null && !export) {
            return;
        }

        if (delay != null && delay > 0) {
            delayExportExecutor.schedule(new Runnable() {
                @Override
                public void run() {
                    doExport();
                }
            }, delay, TimeUnit.MILLISECONDS);
        } else {
            doExport();
        }
    }

配置检查

进到ServiceConfig#doExport方法,其主要是做了配置检查操作

protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        if (exported) {
            return;
        }
        exported = true;
        //步骤一:检测interfaceName合法性
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException(" interface not allow null!");
        }
        checkDefault();
        //步骤二:从providerConfig、moduleConfig、applicationConfig中获取参数
        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;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {
            //反射生成Class,判断interfaceName是否正确
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            //校验methods中方法名称合法性
            checkInterfaceAndMethods(interfaceClass, methods);
            //判断指定的实现类ref是否实现了接口interfaceName
            checkRef();
            generic = Boolean.FALSE.toString();
        }
         //步骤四:判断本地存根类的合法性
        if (local != null) {
            if ("true".equals(local)) {
                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 implementation class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
        if (stub != null) {
            if ("true".equals(stub)) {
                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 implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
        //步骤五:配置如果仍然为空,生成配置、获取抛出异常
        checkApplication();
        checkRegistry();
        checkProtocol();
        appendProperties(this);
        checkStubAndMock(interfaceClass);
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
        //步骤六
        doExportUrls();
        ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
        ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
    }

代码比较长,分为六个步骤来说明

  1. 步骤一:检查interfaceName的合法性,是否为空,interfaceName即为service标签中的interface
<dubbo:service interface="com.dubbo.demo.DemoService"
                   ref="demoService" />
  1. 步骤二:优先从ProviderConfig中获取相关配置(application、module、registries、protocols),如果此时registries、monitor仍然为空(providerConfig中没有),再去ModuleConfig中获取,如果还没有,去ApplicationConfig中获取
  2. 步骤三:判断方法是泛化类型GenericService,如果不是则调用反射加载Class,如果报错了说明interfaceName写的不对,同时也会检查配置的Methods名称是否正确,指定的ref实现类是否实现了interface接口
  3. 步骤四:判断是否配置了本地存根、如果有则本地存根的实现类必为interfaceName+“Local” 或者InterfaceName+“Stub”,同时判断其本地存根类是否实现了指定的接口。本地存根是一个对目标调用接口的封装类,可以在存根类中进行参数校验、返回结果处理等操作,如图DemoServiceStub即为一个提供者端的本地存根,可以在DemoServiceStub进行一些额外增强操作
<dubbo:service interface="com.foo.DemoService" stub="com.foo.DemoServiceStub" />
  1. 步骤五:如果经过了步骤三,仍然有参数为空,则在步骤五中进行新建,如果仍然失败会抛出异常
  2. doExportUrls中进行实际按协议导出服务

多协议服务暴露

注册中心地址获取

doExportUrls中方法实现如下

 private void doExportUrls() {
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }
  1. 先获取注册中心的URL,注册中心的地址获取到是如下的格式,包含了注册中心的ip、端口,应用名称、dubbo版本等信息。 注册中心的URL以registry为协议头。
registry://XXX.XXX.XXX.XXX:2181/com.alibaba.dubbo.registry.RegistryService?application=dubbo-demo-producer&dubbo=2.6.2&pid=60667&registry=zookeeper&timestamp=1573543584310
  1. 在遍历协议,多个协议中分别进行服务导出。Dubbo是支持配置多个协议的(如Dubbo、Thrift、Injvm、Redis等),多个协议使用逗号分隔。

Dubbo-服务导出、暴露实现原理_第8张图片
再就进入到了单个协议的导出方法doExportUrlsFor1Protocol中,这个方法主要将方法相关的参数拼装成一个要导出的URL,然后进行本地导出和服务导出,

URL信息组装

URL信息组装的代码就不贴了,总得来说就是利用一个Map存放Dubbo版本、时间戳等信息,然后从applicationConfig、moduleConfig、providerConfig中获取相关参数
Dubbo-服务导出、暴露实现原理_第9张图片
然后根据Map生成一个URL,看下Map里都有哪些参数,生成的URL又是怎么样的

参数Map,可以看到包含了side(provider)、application项目名称、导出的方法methods、dubbo版本、进程号pid、接口名称、dubbo端口20880、时间戳等信息
Dubbo-服务导出、暴露实现原理_第10张图片

根据参数生成的URL如下

dubbo://192.168.202.83:20880/dubbo.demo.api.IDemoService?anyhost=true&application=dubbo-demo-producer&bind.ip=192.168.202.83&bind.port=20880&dubbo=2.6.2&generic=false&interface=dubbo.demo.api.IDemoService&methods=sayHello&pid=60667&side=provider&timestamp=1573545047968

Dubbo中, URL 作为配置信息的统一格式,所有扩展点都通过传递 URL 携带配置信息

本地导出

有了URL后就要进行服务导出、有的时候服务提供者本身也是消费者,因此将服务暴露到本地能够节省网络IO的时间,提高了方法在本地进行调用时的性能,故首先进行的是本地服务暴露,相关代码如下

如果没有指定配置scope=“remote”,即没有指定服务只暴露到远程时,则进行本地暴露
Dubbo-服务导出、暴露实现原理_第11张图片
本地服务暴露代码如下

private void exportLocal(URL url) {
		//如果protocol不等于injvm,修改协议、ip、端口
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(LOCALHOST)
                    .setPort(0);
            ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
            Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }

步骤比较简单

  1. 如果URL中的protocol不等于injvm,则修改URL中的Protocol为Injvm,同时修改host为127.0.0.1,端口为0。
  2. 调用proxyFactory获取导出接口的代理类Invoker
    Invoker是Dubbo中的一个重要概念,Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。Invoker 是由 ProxyFactory 创建而来,Dubbo 默认的 ProxyFactory 实现类是 JavassistProxyFactory。简单点理解,Invoker其实就是服务接口的一个代理类。通过这个Invoker对接口发起调用。
  3. 调用protocol.export通过SPI机制找到Protocol的实现类(InJvmProtocol)进行export导出,这里首先得找到Protocol对应的实现类,通过在生成的Protocol$Adaptive类中打断点可以知道,返回的Protocol实际是个ProtocolListenerWrapper,其内部持有一个ProtocolFilterWrapper的引用,ProtocolFilterWrapper中最终持有InJvmProtocol的引用,也就是URL种指定的本地协议(InJVM)的实现,name为什么要在最终的InJvmProtocol实现类包装几层呢?下面具体分析

Dubbo-服务导出、暴露实现原理_第12张图片

Filter责任链

先看下ProtocolListenerWrapper的export方法
Dubbo-服务导出、暴露实现原理_第13张图片
最终还是调用ProtocolFilterWrapper#export方法进行导出,进到ProtocolFilterWrapper的export方法
在这里插入图片描述
可以看到ProtocolFilterWrapper中进行导出时,组装了一个Filter责任链,这个Filter就是Dubbo中的过滤器,看下buildInvokerChain的实现
Dubbo-服务导出、暴露实现原理_第14张图片
说明下过滤器责任链组装的思路

  1. 先找到所有激活的过滤器实现类,默认是8个
    Dubbo-服务导出、暴露实现原理_第15张图片
  2. 从后往前遍历filter,每次new出一个Invoker,使得filter[0]的next指向filter[1],filter[1]的next指向filter[2],以此来组成一个责任链

多注册中心远程导出

本地服务导出后,还剩下远程导出。Dubbo的本质也是为了远程调用,这块是重点。
远程暴露代码如下

//如果scope!=local
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
                }
                //注册中心地址不为空,遍历注册中心进行服务暴露
                if (registryURLs != null && !registryURLs.isEmpty()) {
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

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

与本地服务暴露类似,先调用来生成一个Invoker,注意这里用了registryURL来生成Invoker

Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));

生成的Invoker结构如下
在这里插入图片描述

在调用protocol.export进行服务暴露,因为这边的Protocol协议是registry,因此根据SPI,会进入到RegistryProtocol#export方法中,RegistryProtocol是在dubbo、rmi等协议上的封装,加入了注册服务相关逻辑,其代码如下(篇幅原因注册相关代码先不分析)

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //对服务进行暴露
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
		//获取注册中心URL
        URL registryUrl = getRegistryUrl(originInvoker);

        //根据 URL 加载 Registry 实现类,比如 ZookeeperRegistry
        final Registry registry = getRegistry(originInvoker);
        //获取已经注册过的provider的URL
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

        //获取register参数 为true时立马注册
        boolean register = registedProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);
		//进行服务注册
        if (register) {
            register(registryUrl, registedProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

        // 获取订阅 URL
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
        //创建监听器
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        //监听注册中中心Proviver下数据变化
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
    }

注册相关代码先不展开,只看服务导出的doLocalExport方法

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
        String key = getCacheKey(originInvoker);
        ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
        if (exporter == null) {
            synchronized (bounds) {
                exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
                if (exporter == null) {
                    final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));
                    exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);
                    bounds.put(key, exporter);
                }
            }
        }
        return exporter;
    }

此处针对originInvoker生成委托类,originInvoker的协议是我们在XML中配置的协议,如Dubbo协议,而不是registry协议
在这里插入图片描述
因此Protocol.export方法会进入到DubboProtocol#export中,看下具体实现

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        //省略相关代码
        ....
        openServer(url);
        optimizeSerialization(url);
        return exporter;
    }

NettyServer 创建

其核心就是调用了openServer方法开启一个NettyServer,这里的key是服务提供者的ip+端口

private void openServer(URL url) {
        // 服务提供者的ip端口 如192.168.202.83:20880
        String key = url.getAddress();
        //client can export a service which's only for server to invoke
        boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
        if (isServer) {
        	//从缓存中获取ExchangeServer实例
            ExchangeServer server = serverMap.get(key);
            if (server == null) {
            	//没有就创建一个ExchangeServer
                serverMap.put(key, createServer(url));
            } else {
                // server supports reset, use together with override
                server.reset(url);
            }
        }
    }

进到createServer方法中

  1. 首先获取URL中指定的server,如果没指定默认netty实现
  2. 查询SPI中是否有对应server的实现类,没有则抛出异常
  3. 调用Exchangers.bind创建ExchangeServer

ExchangeServer

private ExchangeServer createServer(URL url) {
        // send readonly event when server closes, it's enabled by default
        url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
        // 设置心跳检测时间间隔
        url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
        //获取默认的 底层server参数,默认是netty
        String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
		//判断SPI中是否有对应server的实现类
        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
            throw new RpcException("Unsupported server type: " + str + ", url: " + url);

        url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
        ExchangeServer server;
        try {
	         // 创建 ExchangeServer
            server = Exchangers.bind(url, requestHandler);
        } catch (RemotingException e) {
            throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
        }
        str = url.getParameter(Constants.CLIENT_KEY);
        if (str != null && str.length() > 0) {
            Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
            if (!supportedTypes.contains(str)) {
                throw new RpcException("Unsupported client type: " + str);
            }
        }
        return server;
    }

再看下Exchangers.bind方法,最终调用的是Exchanger#bind方法

public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        }
        if (handler == null) {
            throw new IllegalArgumentException("handler == null");
        }
        url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange");
        return getExchanger(url).bind(url, handler);
    }

默认实现是HeaderExchanger

public class HeaderExchanger implements Exchanger {

    public static final String NAME = "header";
    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

}

Transporter

其内部又调用了Transporters#bind(URL url, ChannelHandler… handlers)

public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
        //省略
        return getTransporter().bind(url, handler);
    }

调用的是Transporter#bind方法,其默认实现为NettyTransporter,跟到NettyTransporter中

public class NettyTransporter implements Transporter {

    public static final String NAME = "netty";

    @Override
    public Server bind(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyServer(url, listener);
    }

}

大家可能会比较懵,这又是Exchanger,又是Transpoter。这俩个类分别是干嘛的?

Exchanger顾名思义是交换层,其封装了请求与响应相关内容。
Transporter的意思是传输层,封装了Grizzly和Mina和Netty的相关实现

NettyServer

简单粗暴,直接new了一个NettyServer,再跟到NettyServer中

其构造函数如下,调用了AbstractServer的父类构造方法

public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
        super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
    }

AbstractServer的构造方法如下,从URL中获取了ip、端口等基本信息,最终还是调用子类的doOpen模板方法来真正的开启服务

public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
        super(url, handler);
        localAddress = getUrl().toInetSocketAddress();
		//绑定的ip
        String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost());
        //绑定的端口
        int bindPort = getUrl().getParameter(Constants.BIND_PORT_KEY, getUrl().getPort());
        if (url.getParameter(Constants.ANYHOST_KEY, false) || NetUtils.isInvalidLocalHost(bindIp)) {
            bindIp = NetUtils.ANYHOST;
        }
        bindAddress = new InetSocketAddress(bindIp, bindPort);
        this.accepts = url.getParameter(Constants.ACCEPTS_KEY, Constants.DEFAULT_ACCEPTS);
        this.idleTimeout = url.getParameter(Constants.IDLE_TIMEOUT_KEY, Constants.DEFAULT_IDLE_TIMEOUT);
        try {
        	//开启Server
            doOpen();
            if (logger.isInfoEnabled()) {
                logger.info("Start " + getClass().getSimpleName() + " bind " + getBindAddress() + ", export " + getLocalAddress());
            }
        } catch (Throwable t) {
            throw new RemotingException(url.toInetSocketAddress(), null, "Failed to bind " + getClass().getSimpleName()
                    + " on " + getLocalAddress() + ", cause: " + t.getMessage(), t);
        }
        //fixme replace this with better method
        DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
        executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
    }

NettyServer中的doOpen实现如下,都在注释中,基本都是NIO相关知识

protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        //创建boss线程池
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        //创建worker线程池
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
        //创建 ServerBootstrap
        bootstrap = new ServerBootstrap(channelFactory);

        final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
        channels = nettyHandler.getChannels();
        // 设置 PipelineFactory
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() {
                NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
                ChannelPipeline pipeline = Channels.pipeline();
                /*int idleTimeout = getIdleTimeout();
                if (idleTimeout > 10000) {
                    pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
                }*/
                pipeline.addLast("decoder", adapter.getDecoder());
                pipeline.addLast("encoder", adapter.getEncoder());
                pipeline.addLast("handler", nettyHandler);
                return pipeline;
            }
        });
        // 绑定到指定ip
        channel = bootstrap.bind(getBindAddress());
    }

你可能感兴趣的:(Dubbo)