Dubbo源码阅读笔记1

服务方初始化


服务方初始化的入口在ServiceConfig类的export方法
这里的初始化是针对一个服务的

public class ServiceConfig<T> extends AbstractServiceConfig {

    private static final long serialVersionUID = 3033787999037024738L;

    /** 
     * 获取自适应扩展点
     * 自适应扩展点和普通扩展点的区别是:普通扩展点的实现类是确定的,自适应扩展点的实现类会根据参数不同变化
     * 这里自适应扩展点用了字节码生成代理类来优化性能,使用动态代理应该也可以实现
     */
    private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
    
    // 代理工厂,用来生成代理类
    private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();

    // 保存随机生成的端口号
    private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();

    // 延迟发布的执行器
    private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
    
    // 生成的服务发布url
    private final List<URL> urls = new ArrayList<URL>();
    private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
    // 接口类型
    private String interfaceName;
    private Class<?> interfaceClass;
    // 接口实现类引用
    private T ref;
    // 服务名称
    private String path;
    // 方法配置
    private List<MethodConfig> methods;
    private ProviderConfig provider;
    private transient volatile boolean exported;

    private transient volatile boolean unexported;

    // 是否泛化引用
    private volatile String generic;
    
    // ...
}

首先判断是否要发布,以及延迟发布

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() {
            public void run() {
                doExport();
            }
        }, delay, TimeUnit.MILLISECONDS);
    } else {
        doExport();
    }
}

先处理各种配置,按优先级覆盖

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!");
    }
    // 处理ProviderConfig
    checkDefault();

    // ...
    // 对配置各种处理
    // ...
    
    // 校验配置
    checkApplication();
    checkRegistry();
    checkProtocol();

    // 最后处理ServiceConfig,优先级最高
    appendProperties(this);
    
    checkStubAndMock(interfaceClass);
    if (path == null || path.length() == 0) {
        path = interfaceName;
    }
    
    // 发布服务
    doExportUrls();
    
    // 把要服务提供者信息封装成model,并设置方法可见性
    ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
    // 放进全局的context中
    ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
}

从配置中取注册中心URL,注册中心可能有多个

private void doExportUrls() {
    List<URL> registryURLs = loadRegistries(true);
    
    // 发布到多种协议中
    for (ProtocolConfig protocolConfig : protocols) {
        doExportUrlsFor1Protocol(protocolConfig, registryURLs);
    }
}
private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
    // ...
    // 将各种配置取出来放到map中,准备组装成URL
    // ...
    
    // 根据优先级取出配置的host和port
    String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
    Integer port = this.findConfigedPorts(protocolConfig, name, map);
    
    // 将所有参数封装到URL对象中, 如: hessian://192.168.9.212:20880/com.alibaba.dubbo.demo.UserService?accesslog=true&anyhost=true&application=demo-provider&bind.ip=192.168.9.212&bind.port=20880&dispatcher=all&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.UserService&methods=getName&pid=20064&revision=1.0.0&side=provider&threadpool=cached&timeout=5000&timestamp=1513650421650&version=1.0.0
    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);
    //配置为none不暴露
    if (!Constants.SCOPE_NONE.equalsIgnoreCase(scope)) {
        //配置不是remote的情况下做本地暴露 (配置为remote,则表示只暴露远程服务)
        if (!Constants.SCOPE_REMOTE.equalsIgnoreCase(scope)) {
            exportLocal(url);
        }
        //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露本地服务)
        if (!Constants.SCOPE_LOCAL.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);
                    }
                    // 接口实现类生成动态代理的接口调用器,此调用器调用的是本地接口实现类,而消费方的调用器是调用远程的方法。
                    // registryURL是注册服务用的URL,url则是调用服务的url
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                    
                    // 包装Invoker
                    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);
}

// 默认情况服务会发布到远程和本地,如果指定了local或remote则只发布到本地或远程
private void exportLocal(URL url) {
    // 将host设置成localhost,这样只能本地调用了
    // 如果本身就指定了injvm则不用再次发布到本地了。
    if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
        // injvm://127.0.0.1/com.alibaba.dubbo.demo.UserService?accesslog=true&anyhost=true&application=demo-provider&bind.ip=192.168.9.212&bind.port=20880&dispatcher=all&dubbo=2.0.0&generic=false&interface=com.alibaba.dubbo.demo.UserService&methods=getName&pid=20064&revision=1.0.0&side=provider&threadpool=cached&timeout=5000&timestamp=1513650421650&version=1.0.0
        URL local = URL.valueOf(url.toFullString())
                .setProtocol(Constants.LOCAL_PROTOCOL)
                .setHost(LOCALHOST)
                .setPort(0);
        
        // 暴露服务, 将接口实现类生成动态代理的接口调用器
        Exporter<?> exporter = protocol.export(
                proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
        exporters.add(exporter);
        logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
    }
}
posted @ 2018-01-25 22:27  开不了囧  阅读(240)  评论(0编辑  收藏  举报