Dubbo源码解析之provider暴露篇

阅读须知

  • dubbo版本:2.6.0
  • spring版本:4.3.8
  • 文章中使用/* */注释的方法会做深入分析

正文

承接provider初始化篇,本篇文章我们来分析provider的暴露过程。
ServiceConfig:

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    String name = protocolConfig.getName();
    if (name == null || name.length() == 0) {
        name = "dubbo";
    }
    Map<String, String> map = new HashMap<String, String>();
    map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
    map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
    if (ConfigUtils.getPid() > 0) {
        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
    }
    // 为几个配置追加参数
    appendParameters(map, application);
    appendParameters(map, module);
    appendParameters(map, provider, Constants.DEFAULT_KEY);
    appendParameters(map, protocolConfig);
    appendParameters(map, this);
    // method配置
    if (methods != null && methods.size() > 0) {
        for (MethodConfig method : methods) {
            // 追加参数
            appendParameters(map, method, method.getName());
            String retryKey = method.getName() + ".retry";
            // retry设置
            if (map.containsKey(retryKey)) {
                String retryValue = map.remove(retryKey);
                if ("false".equals(retryValue)) {
                    map.put(method.getName() + ".retries", "0");
                }
            }
            List<ArgumentConfig> arguments = method.getArguments();
            // 转换参数类型
            if (arguments != null && arguments.size() > 0) {
                for (ArgumentConfig argument : arguments) {
                    if (argument.getType() != null && argument.getType().length() > 0) {
                        Method[] methods = interfaceClass.getMethods();
                        if (methods != null && methods.length > 0) {
                            // 遍历接口的所有方法
                            for (int i = 0; i < methods.length; i++) {
                                String methodName = methods[i].getName();
                                // 目标方法和签名
                                if (methodName.equals(method.getName())) {
                                    Class<?>[] argtypes = methods[i].getParameterTypes();
                                    // 参数索引-1表示未设置
                                    if (argument.getIndex() != -1) {
                                        if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
                                            // 追加参数
                                            appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                                        } else {
                                            throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                        }
                                    } else {
                                        // 方法中的多个回调
                                        for (int j = 0; j < argtypes.length; j++) {
                                            Class<?> argclazz = argtypes[j];
                                            if (argclazz.getName().equals(argument.getType())) {
                                                appendParameters(map, argument, method.getName() + "." + j);
                                                if (argument.getIndex() != -1 && argument.getIndex() != j) {
                                                    throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    } else if (argument.getIndex() != -1) {
                        appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                    } else {
                        throw new IllegalArgumentException("argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
                    }
                }
            }
        }
    }
    // 判断服务是否是GenericService类型
    if (ProtocolUtils.isGeneric(generic)) {
        map.put("generic", generic);
        map.put("methods", Constants.ANY_VALUE);
    } else {
        String revision = Version.getVersion(interfaceClass, version);
        if (revision != null && revision.length() > 0) {
            map.put("revision", revision);
        }
        // 使用javaassist生成接口的包装类,获取方法名称
        String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
        if (methods.length == 0) {
            logger.warn("NO method found in service interface " + interfaceClass.getName());
            map.put("methods", Constants.ANY_VALUE);
        } else {
            map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
        }
    }
    // token配置
    if (!ConfigUtils.isEmpty(token)) {
        if (ConfigUtils.isDefault(token)) {
            map.put("token", UUID.randomUUID().toString());
        } else {
            map.put("token", token);
        }
    }
    // 协议的名称配置为injvm
    if ("injvm".equals(protocolConfig.getName())) {
        protocolConfig.setRegister(false);
        map.put("notify", "false");
    }
    // contextPath配置
    String contextPath = protocolConfig.getContextpath();
    if ((contextPath == null || contextPath.length() == 0) && provider != null) {
        contextPath = provider.getContextpath();
    }
    /* 注册并绑定服务提供者的IP地址,可以单独配置 */
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    /* 为提供者注册端口和绑定端口,可以单独配置 */
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);
    if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
        .hasExtension(url.getProtocol())) {
        url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
        .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
    }
    String scope = url.getParameter(Constants.SCOPE_KEY);
    // scope配置为none不暴露服务
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
            /* 没有配置为remote,暴露本地服务 */
            exportLocal(url);
        }
        // 没有配置为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.size() > 0) {
                for (URL registryURL : registryURLs) {
                    url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                    // 加载监视器地址
                    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<?> 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);
            }
        }
    }
    this.urls.add(url);
}

ServiceConfig:

private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
    boolean anyhost = false;
    // 从系统属性中获取dubbo ip绑定配置,如果是非法ip(空、localhost、0.0.0.0、127.*.*.*都属于非法),抛出异常
    String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND);
    // 如果从环境中没有获取到配置,继续寻找
    if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
        throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind);
    }
    if (hostToBind == null || hostToBind.length() == 0) {
        hostToBind = protocolConfig.getHost(); // 从协议配置中获取
        if (provider != null && (hostToBind == null || hostToBind.length() == 0)) {
            // 到这里没有找到则再次尝试从provider配置中获取
            hostToBind = provider.getHost();
        }
        if (isInvalidLocalHost(hostToBind)) {
            anyhost = true;
            try {
                // 如果到这里获取的ip为空或者非法,则尝试赋值为本地主机地址
                hostToBind = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.warn(e.getMessage(), e);
            }
            if (isInvalidLocalHost(hostToBind)) {
                if (registryURLs != null && registryURLs.size() > 0) {
                    for (URL registryURL : registryURLs) {
                        try {
                            Socket socket = new Socket();
                            try {
                                SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                                socket.connect(addr, 1000);
                                hostToBind = socket.getLocalAddress().getHostAddress();
                                break;
                            } finally {
                                try {
                                    socket.close();
                                } catch (Throwable e) {
                                }
                            }
                        } catch (Exception e) {
                            logger.warn(e.getMessage(), e);
                        }
                    }
                }
                if (isInvalidLocalHost(hostToBind)) {
                    // 如果到这里获取的ip还是为空或者非法,则尝试从本地网卡查找第一个有效的IP,如果没有获取到,则赋值为127.0.0.1
                    hostToBind = getLocalHost();
                }
            }
        }
    }
    map.put(Constants.BIND_IP_KEY, hostToBind);
    // 尝试从系统属性中获取注册中心ip配置
    String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY);
    if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
        throw new IllegalArgumentException("Specified invalid registry ip from property:" + Constants.DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
    } else if (hostToRegistry == null || hostToRegistry.length() == 0) {
        // 没有从系统环境中获取到则赋值为绑定的ip
        hostToRegistry = hostToBind;
    }
    map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost));
    return hostToRegistry;
}

ServiceConfig:

private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
    Integer portToBind = null;
    // 从系统环境中解析绑定的端口
    String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
    // 将端口转换成int类型并判断是否合法(在0-65535范围之内)
    portToBind = parsePort(port);
    // 如果没有找到绑定端口的配置,继续寻找
    if (portToBind == null) {
        // 从protocol配置中寻找
        portToBind = protocolConfig.getPort();
        if (provider != null && (portToBind == null || portToBind == 0)) {
            // 从provider配置中寻找
            portToBind = provider.getPort();
        }
        // 默认protocol配置中寻找
        final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
        if (portToBind == null || portToBind == 0) {
            portToBind = defaultPort;
        }
        if (portToBind == null || portToBind <= 0) {
            // 获取随机端口,从缓存中获取,缓存中没有会返回Integer.MIN
            portToBind = getRandomPort(name);
            if (portToBind == null || portToBind < 0) {
                // 获取可用端口
                portToBind = getAvailablePort(defaultPort);
                // 放入缓存
                putRandomPort(name, portToBind);
            }
            logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
        }
    }
    map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));
    // 注册中心端口,默认情况下不用作绑定端口
    String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
    Integer portToRegistry = parsePort(portToRegistryStr);
    if (portToRegistry == null) {
        portToRegistry = portToBind;
    }
    return portToRegistry;
}

ServiceConfig:

private void exportLocal(URL url) {
    // 判断协议是否不是injvm
    if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
        URL local = URL.valueOf(url.toFullString())
        .setProtocol(Constants.LOCAL_PROTOCOL) // 设置injvm协议
        .setHost(LOCALHOST) // 127.0.0.1
        .setPort(0);
        ServiceClassHolder.getInstance().pushServiceClass(getServiceClass(ref));
        /* 获取invoker,暴露服务 */
        Exporter<?> exporter = protocol.export(
            proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
        exporters.add(exporter); // 添加到已暴露的服务列表中
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    }
}

在Dubbo源码解析之扩展点(ExtensionLoader)篇中,我们分析扩展点的实例化流程,这里将URL的protocol设置为injvm,所以这里的protocol为InjvmProtocol,并用ProtocolFilterWrapper和ProtocolListenerWrapper对protocol进行了包装(其他Protocol的扩展点如RegistryProtocol也同样会经过这两层包装)。
JavassistProxyFactory:

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);
        }
    };
}

export暴露流程首先会经过包装类的处理:
ProtocolFilterWrapper:

public <T> Exporter <T> export (Invoker <T> invoker) throws RpcException {
    // RegistryProtocol忽略这层包装
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    /* 构建Invoker调用链,调用下一个包装过程继续进行export */
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

ProtocolFilterWrapper:

private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
    Invoker<T> last = invoker;
    // 获取所有自动激活的Filter
    List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
    if (filters.size() > 0) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new Invoker<T>() {
                public Class<T> getInterface() {
                    return invoker.getInterface();
                }
                public URL getUrl() {
                    return invoker.getUrl();
                }
                public boolean isAvailable() {
                    return invoker.isAvailable();
                }
                public Result invoke(Invocation invocation) throws RpcException {
                    // invoker调用时首先经过filter的过滤
                    return filter.invoke(next, invocation);
                }
                public void destroy() {
                    invoker.destroy();
                }
                @Override
                public String toString() {
                    return invoker.toString();
                }
            };
        }
    }
    return last;
}

这里的Filter有很多,EchoFilter、ClassLoaderFilter、GenericFIlter、ContextFilter、TraceFilter、TimeoutFilter、MonitorFilter、ExceptionFilter,功能不一一赘述,有兴趣的读者自行查看。接下来会经过下一个Protocol包装类:
ProtocolListenerWrapper:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    // RegistryProtocol忽略本次包装
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    /* 添加ExporterListener,暴露Invoker */
    return new ListenerExporterWrapper<T>(protocol.export(invoker),
            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}

ExporterListener的作用是监听Exporter的export和unexport动作,dubbo本身没有具体实现,可以进行相应的扩展。接下来会真正的进入InjvmProtocol

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap);
}

InjvmExporter的作用比较简单,就是简单的在exporterMap中添加或删除key和自身Exporter的关系。本次服务暴露后,接下来是向注册中心暴露服务,URL的protocol设置为registry,所以这里的Protocol扩展点为RegistryProtocol,上面我们看到包装类都忽略了RegistryProtocol,直接来看RegistryProtocol的export实现:
RegistryProtocol:

public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    /* 暴露invoker */
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);
    // 从invoker中获取之前构建好的url
    URL registryUrl = getRegistryUrl(originInvoker);
    // 获取注册中心
    final Registry registry = getRegistry(originInvoker);
    // 获取已经注册的提供者的url
    final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);
    // 判断是否延迟发布
    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);
    // 订阅
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
    // 确保每次暴露都会返回一个新的实例
    return new Exporter<T>() {
        public Invoker<T> getInvoker() {
            return exporter.getInvoker();
        }
        public void unexport() {
            try {
                exporter.unexport();
            } catch (Throwable t) {
                logger.warn(t.getMessage(), t);
            }
            try {
                registry.unregister(registedProviderUrl);
            } catch (Throwable t) {
                logger.warn(t.getMessage(), t);
            }
            try {
                overrideListeners.remove(overrideSubscribeUrl);
                registry.unsubscribe(overrideSubscribeUrl, overrideSubscribeListener);
            } catch (Throwable t) {
                logger.warn(t.getMessage(), t);
            }
        }
    };
}

这里有关注册中心的获取、注册、订阅等相关操作,我们用单独的文章来分析,详见:传送门
RegistryProtocol:

private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker) {
    String key = getCacheKey(originInvoker); // 缓存key,就是providerUrl
    // bounds为providerurl和exporter的映射,目的是为了解决RMI重复出现端口冲突的问题,已经暴露的服务不再暴露。
    ExporterChangeableWrapper<T> exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
    if (exporter == null) {
        synchronized (bounds) {
            exporter = (ExporterChangeableWrapper<T>) bounds.get(key);
            if (exporter == null) {
                // invokerDelegete的URL protocol为dubbo
                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;
}

DubboProtocol:

public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    URL url = invoker.getUrl();
    String key = serviceKey(url); // 格式(分组/接口全称:服务版本:端口),接口和端口是一定存在的,分组和服务版本不一定
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
    exporterMap.put(key, exporter);
    // 是否为调度事件暴露一个stub服务
    Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY, Constants.DEFAULT_STUB_EVENT);
    Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
    if (isStubSupportEvent && !isCallbackservice) {
        String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
        if (stubServiceMethods == null || stubServiceMethods.length() == 0) {
            if (logger.isWarnEnabled()) {
                logger.warn(new IllegalStateException("consumer [" + url.getParameter(Constants.INTERFACE_KEY) +
                    "], has set stubproxy support event ,but no stub methods founded."));
            }
        } else {
            stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
        }
    }
    /* 开启服务 */
    openServer(url);
    optimizeSerialization(url); // 优化序列化
    return exporter;
}

DubboProtocol:

private void openServer(URL url) {
    String key = url.getAddress();
    // 客户端可以暴露仅用于服务端调用的服务
    boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
    if (isServer) {
        ExchangeServer server = serverMap.get(key);
        if (server == null) {
            /* 创建服务 */
            serverMap.put(key, createServer(url));
        } else {
            // 服务端支持重置,与重写一起使用
            server.reset(url);
        }
    }
}

DubboProtocol:

private ExchangeServer createServer(URL url) {
    // 当服务器关闭时发送只读事件,默认为true
    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);
    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 {
        /* 绑定 */
        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:

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");
    /* 获取exchanger(默认为HeaderExchanger),绑定 */
    return getExchanger(url).bind(url, handler);
}

HeaderExchanger:

public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
    /* 绑定,构建server */
    return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

Transporters:

public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException {
    if (url == null) {
        throw new IllegalArgumentException("url == null");
    }
    if (handlers == null || handlers.length == 0) {
        throw new IllegalArgumentException("handlers == null");
    }
    ChannelHandler handler;
    if (handlers.length == 1) {
        handler = handlers[0];
    } else {
        handler = new ChannelHandlerDispatcher(handlers);
    }
    /* 获取Transporter,绑定 */
    return getTransporter().bind(url, handler);
}

NettyTransporter:

public Server bind(URL url, ChannelHandler listener) throws RemotingException {
    /* 构建NettyServer */
    return new NettyServer(url, listener);
}

NettyServer:

public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
    /* 为url设置线程名称,包装handler,调用父类构造方法初始化 */
    super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}

AbstractServer:

public AbstractServer(URL url, ChannelHandler handler) throws RemotingException {
    super(url, handler);
    localAddress = getUrl().toInetSocketAddress();
    String bindIp = getUrl().getParameter(Constants.BIND_IP_KEY, getUrl().getHost()); // ip
    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 {
        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);
    }
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    executor = (ExecutorService) dataStore.get(Constants.EXECUTOR_SERVICE_COMPONENT_KEY, Integer.toString(url.getPort()));
}

NettyServer:

protected void doOpen() throws Throwable {
    NettyHelper.setNettyLoggerFactory();
    ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true)); // boss线程池
    ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true)); // worker线程池
    ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
    bootstrap = new ServerBootstrap(channelFactory);
    final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
    channels = nettyHandler.getChannels();
    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
            ChannelPipeline pipeline = Channels.pipeline();
            // 解码器
            pipeline.addLast("decoder", adapter.getDecoder());
            // 编码器
            pipeline.addLast("encoder", adapter.getEncoder());
            // 处理器
            pipeline.addLast("handler", nettyHandler);
            return pipeline;
        }
    });
    // 绑定
    channel = bootstrap.bind(getBindAddress());
}

这我们看到了dubbo使用netty来开启服务,需要读者对netty的知识有一定的了解,这里使用的是netty3,dubbo目前已经有netty4的使用,在com.alibaba.dubbo.remoting.transport.netty4包下。这里我们要对handler的包装过程有清楚的认知,大致如下:

DubboProtocol.requestHandler --> DecodeHandler --> HeaderExchangeHandler --> MultiMessageHandler --> HeartbeatHandler --> AllChannelHandler --> NettyHandler

到这里,整个服务的暴露就完成了,我们是从本地服务暴露开始分析的,用了很大篇幅来讲解这个过程,远程服务暴露也是同样复用这个流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值