Spring Cloud Alibaba 教程 | Dubbo(六):服务暴露

框架设计

下图是Dubbo框架的整体设计图,总共分为了10层,其中Service层直接和用户接触,代表了一个个的服务接口。
在这里插入图片描述

  • config 配置层:对外配置接口,以 ServiceConfig, ReferenceConfig为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类
  • proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy为中心,扩展接口为 ProxyFactory
  • registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory,Registry, RegistryService
  • cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster,Directory, Router, LoadBalance
  • monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory,
    Monitor, MonitorService
  • protocol 远程调用层:封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol,Invoker, Exporter
  • exchange 信息交换层:封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer
  • transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel,
    Transporter, Client, Server, Codec
  • serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization, ObjectInput,ObjectOutput, ThreadPool

服务暴露流程

了解了Dubbo的整体设计图之后,我们就可以先来解析服务的暴露流程,服务暴露的核心是“Protocol + Invoker + Exporter”:

  • Invoker可以简单理解为一个暴露的服务接口实例对象,是Dubbo框架实体域,所有模型都会向他靠拢,并且可以对它发起invoke()调用。
  • Protocol代表了服务暴露使用的协议,例如dubbo协议、HTTP协议、REST协议等等,使用 < dubbo:protocol>指定使用的具体暴露协议,例如:< dubbo:protocol name=“dubbo” port=“20880”/>
  • Exporter代表了一个已经成功暴露的服务,可以通过Protocol将Invoker转换成Exporter,Exporter<?>
    exporter = protocol.export(invoker)。
public interface Invoker<T> extends Node {

    Class<T> getInterface();
    
    Result invoke(Invocation invocation) throws RpcException;
    
}
@SPI("dubbo")
public interface Protocol {

    int getDefaultPort();
    
    /**Export service for remote invocation*/
    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
    
    /**Refer a remote service*/
    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
    
    void destroy();
    
}
public interface Exporter<T> {

    Invoker<T> getInvoker();
    
    void unexport();
    
}

下图是Dubbo服务暴露的流程图,首先一个服务接口对应一个ServiceConfig实例对象,ServiceConfig包含了对服务实现类对象的引用。服务接口的暴露分为本地暴露和远程暴露,本地暴露使用injvm协议,远程暴露使用dubbo等协议,本地暴露是为了在可能存在本地服务引用了同一个JVM内部自身服务的情况下,避免跨网络远程调用,消费者可以直接调用同一个JVM内部的服务,远程暴露则提供了跨内存空间、网络空间的服务调用能力。尽管远程暴露要比本地暴露复杂很多,但是总体上都可以分为两大步,第一步通过ProxyFactory将服务实例转换成Invoker,第二步通过Protocol将Invoker转换成Exporter。
在这里插入图片描述
服务暴露的起点在ServiceConfig类export()方法,那么该方法是如何被调用的呢?

Dubbo整合了Spring框架,使用了spring的标签扩展功能,通过DubboNamespaceHandler定义了标签解析器。在我们启动服务的时候Spring会解析我们的dubbo配置文件生成BeanDefinition,DubboBeanDefinitionParser负责对dubbo命名空间的解析,在解析的过程中会为每一个服务接口(< dubbo:service>)生成一个ServiceBean对象,ServiceBean实现了ApplicationListener接口。
在applicationContext启动的refresh阶段会广播ApplicationEvent事件,触发ApplicatinListener.onApplicationEvent()方法的执行,所以触发了ServiceBean.onApplicationEvent()的执行。ServiceBean继承了ServiceConfig,最终会调用到它的export()方法。

@Override
 public void onApplicationEvent(ContextRefreshedEvent event) {
     if (isDelay() && !isExported() && !isUnexported()) {
         if (logger.isInfoEnabled()) {
             logger.info("The service ready on spring started. service: " + getInterface());
         }
         export();
     }
 }

接着依次调用ServiceConfig类:export()–>doExport()–>doExportUrls()

@SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
    //获取所有注册中心实例地址
    List<URL> registryURLs = loadRegistries(true); //@1
    for (ProtocolConfig protocolConfig : protocols) {
        //针对多个协议时,对每个协议依次暴露(Dubbo、REST)
        doExportUrlsFor1Protocol(protocolConfig, registryURLs); //@2
    }
}

@1:获取用户配置的所有注册中心地址集合,使用< dubbo:registry>标签配置注册中心地址,例如
<dubbo:registry protocol=“zookeeper” address=“10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181” />,更多关于zookeeper注册中心配置方式可以到官网上查阅这篇文章
http://dubbo.apache.org/zh-cn/docs/user/references/registry/zookeeper.html

@2:Dubbo框架允许用户使用多次< dubbo:protocol>标签去定义多个不同的协议,将同一个服务暴露在多个协议上。

private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    String name = protocolConfig.getName();
    if (name == null || name.length() == 0) {
        name = "dubbo";
    }

    //读取配置信息到 map
    Map<String, String> map = new HashMap<String, String>(); //@1
    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()));

    //省略部分代码......

    //通过map组装服务URL
    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); //@2

    String scope = url.getParameter(Constants.SCOPE_KEY); //scope=null
    // don't export when none is configured
    if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

        // export to local if the config is not remote (export to remote only when config is remote)
        if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
            //服务本地暴露
            exportLocal(url); //@3
        }
        // export to remote if the config is not local (export to local only when config is 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());//@4
                    }
                    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()));//@5
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);//@6

                    //通过Protocol将Invoker转换成Exporter
                    //执行RegistryProtocol.export()方法,里面包含了通过注册中心实例Registry执行发布和订阅操作
                    Exporter<?> exporter = protocol.export(wrapperInvoker);//@7
                    exporters.add(exporter);//@8
                }
            } 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);
}

@1:Map<String, String> map 负责存储各种配置信息。
@2:通过map构造出服务URL。
@3:服务本地暴露。
@4:调用信息上报监控中心。
@5:ProxyFactory通过ref引用对象和URL将服务接口转换成Invoker。
@6:对Invoker进行进一步封装成DelegateProviderMetaDataInvoker。
@7:通过Protocol将Invoker转换成Exporter。
@8:存储exporter。

本地暴露

服务本地暴露逻辑都在exportLocal(url)方法里面

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

@1:修改服务URL的协议、地址和端口,协议为"injvm"。
@2:可以拆分成两部分:proxyFactory.getInvoker()和protocol.export()。
@3:将生成的exporter对象存储到exporters,exporters同时存储本地exporter和远程exporter。

ProxyFactory是一个扩展接口,实现类有JavassistProxyFactory和JdkProxyFactory,默认使用 JavassistProxyFactory。

@SPI("javassist")
public interface ProxyFactory {
    @Adaptive({Constants.PROXY_KEY})
    <T> T getProxy(Invoker<T> invoker) throws RpcException;
    @Adaptive({Constants.PROXY_KEY})
    <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
}
public class JavassistProxyFactory extends AbstractProxyFactory {
    @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        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);
            }
        };
    }

}

在getInvoker()方法里通过实现类引用对象proxy、Class和URL构造AbstractProxyInvoker对象,并通过获取Wrapper实例处理doInvoke()回调方法。

通过ProxyFactory生成Invoker对象之后,接下里执行protocol.export(invoker)方法,前面介绍过Protocol是一个扩展接口,InjvmProtocol、RegistryProtocol和DubboProtocol都实现了该扩展接口,InjvmProtocol用于本地暴露,RegistryProtocol和DubboProtocol用于远程暴露。
此时protocol是一个动态生成的Protocol$Adaptive实例对象,因为Invoker的协议为injvm,所以获取到InjvmProtocol目标对象,同时Protocol又包含了ProtocolListenerWrapper和ProtocolFilterWrapper这两个包装扩展类,所以执行顺序是ProtocolListenerWrapper.export()–>ProtocolFilterWrapper.export()–>InjvmProtocol.exprot()

public class ProtocolListenerWrapper implements Protocol {

    private final Protocol protocol;

    public ProtocolListenerWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }

	@Override
	public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
		//判断协议是否是"registry"
	    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
	        return protocol.export(invoker);
	    }
	    //将Exporter包装成ListenerExporterWrapper对象
	    return new ListenerExporterWrapper<T>(protocol.export(invoker),
	            Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
	                    .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
	}

}

在创建ListenerExporterWrapper实例时,先执行protocol.export(invoker)进入到ProtocolFilterWrapper.export()

public class ProtocolFilterWrapper implements Protocol {

    private final Protocol protocol;

    public ProtocolFilterWrapper(Protocol protocol) {
        if (protocol == null) {
            throw new IllegalArgumentException("protocol == null");
        }
        this.protocol = protocol;
    }

    @Override
    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
        if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
            return protocol.export(invoker);
        }
        return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
    }
    
	private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
        Invoker<T> last = invoker;
        //获取到8个过滤器
        List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
        if (!filters.isEmpty()) {
            for (int i = filters.size() - 1; i >= 0; i--) {
                final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    @Override
                    public Class<T> getInterface() {
                        return invoker.getInterface();
                    }

                    @Override
                    public URL getUrl() {
                        return invoker.getUrl();
                    }

                    @Override
                    public boolean isAvailable() {
                        return invoker.isAvailable();
                    }

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                        return filter.invoke(next, invocation);
                    }

                    @Override
                    public void destroy() {
                        invoker.destroy();
                    }

                    @Override
                    public String toString() {
                        return invoker.toString();
                    }
                };
            }
        }
        return last;
    }
}

首先先执行buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER),创建8个Invoker并依次前后拼接,所以我们的服务接口Invoker将位于该Invoker链的最后面,目的在于当对服务Invoker实例发起invoke调用时,可以在调用之前做过滤处理,这块内容后面会详细介绍。
在这里插入图片描述
接下来进入到InjvmProtocol.export()方法,该方法直接创建一个InjvmExporter实例对象。

public class InjvmProtocol extends AbstractProtocol implements Protocol {

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

在InjvmExporter构造方法里面将服务InjvmExporter实例存储到exporterMap,key是接口全类名。exporterMap是在AbstractProtocol实例化的。

class InjvmExporter<T> extends AbstractExporter<T> {

    private final String key;

    /**存储服务接口对应的Exporter*/
    private final Map<String, Exporter<?>> exporterMap;

    InjvmExporter(Invoker<T> invoker, String key, Map<String, Exporter<?>> exporterMap) {
        super(invoker);
        this.key = key;
        this.exporterMap = exporterMap;
        exporterMap.put(key, this);
    }
    
}
public abstract class AbstractProtocol implements Protocol {

    protected final Map<String, Exporter<?>> exporterMap = new ConcurrentHashMap<String, Exporter<?>>();

这样服务本地暴露逻辑exportLocal(URL url)已经完成。

远程暴露

无论是远程暴露还是本地暴露,总体流程都是先通过ProxyFactory将服务引用对象转换成Invoker,然后通过Protocol将Invoker转换成Exporter,不过远程暴露的内部逻辑要复杂一些。

//服务远程暴露
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);

//通过Protocol将Invoker转换成Exporter
//执行RegistryProtocol.export()方法,里面包含了通过注册中心实例Registry执行发布和订阅操作
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);

通过ProxyFactory获取到Invoker(AbstractInvoker)这一步和本地暴露是一样的,只是本地暴露的URL协议是injvm,而远程暴露的URL则是registry。
由于协议不一样,下一步执行protocol.export(wrapperInvoker)获取目标执行目标就变成了RegistryProtocol
所以执行顺序是ProtocolListenerWrapper.export()–>ProtocolFilterWrapper.export()–>RegistryProtocol.exprot()。

@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    if (Constants.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(), Constants.EXPORTER_LISTENER_KEY)));
}

@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

因为此时URL协议是registry所以两个包装扩展类没有做任何处理,直接调用了目标对象RegistryProtocol.export()方法。

@Override
public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
    //export invoker
    final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker); //@1

    URL registryUrl = getRegistryUrl(originInvoker);

    //registry provider
    final Registry registry = getRegistry(originInvoker);//@2
    final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

    //to judge to delay publish whether or not
    boolean register = registedProviderUrl.getParameter("register", true);

    ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);//@3

    if (register) {
        //注册
        register(registryUrl, registedProviderUrl);//@4
        ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
    }

    //创建OverrideListener元数据监听器
    // Subscribe the override data
    // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover.
    final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
    final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);//@5
    overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
    //订阅
    registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);//@6
    //Ensure that a new exporter instance is returned every time export
    return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
}

@1:负责创建Exporter,并将Exporter存储到exporterMap,这个整体上的逻辑和本地暴露是一样的,同时会通过底层的Exchange层、Transport层和Serialize层完成暴露TCP端口监听服务。
@2:通过注册中心地址registryUrl获取到Registry实例对象,Registry内部是通过RegistryFactory获取的,关于Registry和RegistryFactory内容上一篇文章已经讲解过。

private Registry getRegistry(final Invoker<?> originInvoker) {
    URL registryUrl = getRegistryUrl(originInvoker);
    return registryFactory.getRegistry(registryUrl);
}

@3:存储服务接口和Invoker对应关系。

public class ProviderConsumerRegTable {

    /**存储服务接口全类名对应的Invoker*/
    public static ConcurrentHashMap<String, Set<ProviderInvokerWrapper>> providerInvokers = new ConcurrentHashMap<String, Set<ProviderInvokerWrapper>>();
    /**存储消费接口全类名对应的Invoker*/
    public static ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>> consumerInvokers = new ConcurrentHashMap<String, Set<ConsumerInvokerWrapper>>();

    public static void registerProvider(Invoker invoker, URL registryUrl, URL providerUrl) {
        ProviderInvokerWrapper wrapperInvoker = new ProviderInvokerWrapper(invoker, registryUrl, providerUrl);
        String serviceUniqueName = providerUrl.getServiceKey();
        Set<ProviderInvokerWrapper> invokers = providerInvokers.get(serviceUniqueName);
        if (invokers == null) {
            providerInvokers.putIfAbsent(serviceUniqueName, new ConcurrentHashSet<ProviderInvokerWrapper>());
            invokers = providerInvokers.get(serviceUniqueName);
        }
        invokers.add(wrapperInvoker);
    }
}

@4:执行服务注册逻辑,里面的内容已经在上一篇文章中讲解过。
@5:创建元数据监听器对象OverrideListener(监听configurators节点) 。
@6:执行订阅逻辑,里面的内容已经在上一篇文章中讲解过。

服务远程暴露整体逻辑已经讲完,下面对@1步骤的RegistryProtocol.doLocalExport(originInvoker)方法进行详细分析。

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) {
                //originInvoker registry://127.0.0.1:2181/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.0.0&export=dubbo
                final Invoker<?> invokerDelegete = new InvokerDelegete<T>(originInvoker, getProviderUrl(originInvoker));//@1
                //通过exporter和originInvoker生产ExporterChangeableWrapper对象
                exporter = new ExporterChangeableWrapper<T>((Exporter<T>) protocol.export(invokerDelegete), originInvoker);//@2
                bounds.put(key, exporter);
            }
        }
    }
    return exporter;
}

@1:originInvoker是协议是registry,通过getProviderUrl(originInvoker)获取export参数值dubbo,构建InvokerDelegete,InvokerDelegete包含了一个URL成员变量,协议以dubbo开头。

@2:通过exporter和originInvoker生成ExporterChangeableWrapper对象,RegistryProtocol又包含了一个protocol对象,但RegistryProtocol本身并不是包装扩展类,此时通过protocol(Protocol$Adaptive)获取的目标对象是DubboProtocol,所以protocol.export(invokerDelegete)的执行顺序是 ProtocolListenerWrapper.export()–>ProtocolFilterWrapper.export()–>DubboProtocol.exprot()。

@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    //判断协议是否是registry
    if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
        return protocol.export(invoker);
    }
    return protocol.export(buildInvokerChain(invoker, Constants.SERVICE_FILTER_KEY, Constants.PROVIDER));
}

在执行ProtocolFilterWrapper.export()时,将会执行buildInvokerChain()创建Invoker过滤器链,这部分内容已经在本地暴露时讲解过。

@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
    URL url = invoker.getUrl();

    // export service.
    String key = serviceKey(url);
    //创建DubboExporter,存储到exporterMap
    DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);//@1
    exporterMap.put(key, exporter);

    //export an stub service for dispatching event
    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);//@2
    optimizeSerialization(url);
    return exporter;
}

@1:创建DubboExporter,存储到exporterMap。
@2:打开服务,里面将通过底层的exchange信息交换层、transport网络传输层、serialize数据序列化层
开启监听服务,等待远程服务连接和数据传输交互。

private void openServer(URL url) {
    // find server.
    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 server = serverMap.get(key);
        if (server == null) {
            serverMap.put(key, createServer(url));//创建ExchangeServer 
        } else {
            // server supports reset, use together with override
            server.reset(url);
        }
    }
}

该方法通过获取到本地服务地址去创建ExchangeServer,并将其存储到Map<String, ExchangeServer> serverMap。

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());
    // enable heartbeat by default
    url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
    String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);//@1

    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);//@2
    } 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;
}

@1:默认使用远程通讯框架是netty。
@2:创建TCP端口监听服务。

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

getExchanger(url)目的是通过url获取Exchanger扩展接口实现对象HeaderExchanger。

@SPI(HeaderExchanger.NAME)
public interface Exchanger {
    @Adaptive({Constants.EXCHANGER_KEY})
    ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException;
    
    @Adaptive({Constants.EXCHANGER_KEY})
    ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException;
}
public class HeaderExchanger implements Exchanger {

    public static final String NAME = "header";

    @Override
    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
    }

    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

}

1、创建通道处理器:new DecodeHandler(new HeaderExchangeHandler(handler))

2、Transporters.bind(url, channelHandler),Netty服务的开启交给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);
    }
    return getTransporter().bind(url, handler);
}

通过getTransporter()获取的Transporter扩展接口实例对象

public static Transporter getTransporter() {
    return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
}
@SPI("netty")
public interface Transporter {

    @Adaptive({Constants.SERVER_KEY, Constants.TRANSPORTER_KEY})
    Server bind(URL url, ChannelHandler handler) throws RemotingException;

    @Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
    Client connect(URL url, ChannelHandler handler) throws RemotingException;
}

Transporter有四个实现类:MinaTransporter、NettyTransporter(NAME = “netty”)、NettyTransporter(NAME = “netty4”)和GrizzlyTransporter,默认使用NettyTransporter(NAME = “netty”)。

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

    @Override
    public Client connect(URL url, ChannelHandler listener) throws RemotingException {
        return new NettyClient(url, listener);
    }

}

public class NettyServer extends AbstractServer implements Server {

    private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);

    private Map<String, Channel> channels; // <ip:port, channel>

    private ServerBootstrap bootstrap;

    private org.jboss.netty.channel.Channel channel;

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

    @Override
    protected void doOpen() throws Throwable {
        NettyHelper.setNettyLoggerFactory();
        ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
        ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
        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();
        // https://issues.jboss.org/browse/NETTY-365
        // https://issues.jboss.org/browse/NETTY-379
        // final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
        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;
            }
        });
        // bind
        channel = bootstrap.bind(getBindAddress());
    }
}

NettyServer继承了AbstractServer抽象类,在AbstractServer构造方法里面,调用了模板方法doOpen(),交给子类NettyServer去实现开启TCP端口监听服务。

关注公众号了解更多原创博文

Alt

发布了122 篇原创文章 · 获赞 127 · 访问量 93万+

猜你喜欢

转载自blog.csdn.net/u010739551/article/details/104318632