dubbo server启动

2018-01-18 22:25:49

源码分析基于dubbo 2.6.0

从DubboNamespaceHandler可以看到,dubbo的标签都是由DubboBeanDefinitionParser解析。如

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

需要关注一下DubboBeanDefinitionParser对service标签的处理

RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
String id = element.getAttribute("id");


...
else if (ServiceBean.class.equals(beanClass)) {
    String className = element.getAttribute("class");
    if (className != null && className.length() > 0) {
        RootBeanDefinition classDefinition = new RootBeanDefinition();
        classDefinition.setBeanClass(ReflectUtils.forName(className));
        classDefinition.setLazyInit(false);
        parseProperties(element.getChildNodes(), classDefinition);
        beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
    }
}

这里的beanClass就是DubboBeanDefinitionParser创建时的参数,这里就是ServiceBean.class。
从上面代码可以看到,dubbo中的service都是ServiceBean, 如

<dubbo:service id="dubboHelloService" interface="com.dubbo.start.service.HelloService" class="com.dubbo.start.service.HelloServiceImpl">

则dubboHelloService解析为一个ServiceBean, ServiceBean中ref属性为HelloServiceImpl。(不要误以为dubboHelloService解析为HelloServiceImpl,这里和spring不一样)

ServiceBean实现了ApplicationListener
spring启动时,会触发ServiceBean.onApplicationEvent方法,最终调用到父类ServiceConfig.doExport方法

doExport方法前面花费了很大段代码进行参数检查,然后调用doExportUrls方法

    private void doExportUrls() {
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

对每一种协议protocol,都要doExportUrlsFor1Protocol。
我们一般使用dubbo protocol, <dubbo:protocol name="..." port="...">

doExportUrlsFor1Protocol 花了很多代码将interface,method,timeout,validation这些参数放到一个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);        

// 扩展
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);

if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

    // 暴露本地接口
    if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
        exportLocal(url);
    }
    // 暴露远程接口
    if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {

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

暴露本地接口使用InjvmProtocol处理。

这里只关注远程接口的暴露。

registryURLs的格式为registry://(zk ip):(zk prot)/com.alibaba.dubbo.registry.RegistryService?registry=zookeeper&..., 所以protocol.export会调用RegistryProtocol.export。dubbo将上下文环境存放在url参数中,所以看dubbo源码也得分析它的url格式。

dubbo zookeeper的注册会在下一篇文章讲解。