dubbo源码——服务提供者的服务暴露过程(一)

一、前言

最近在学习dubbo源码,故写下学习dubbo时的一些心得。。

dubbo源码版本:2.6.1

二、自定义标签

<dubbo:xxx/>标签是Spring的自定义标签,可以查看dubbo.jar包下的META-INF->spring.handlers

//file:spring.handlers
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

它是通过DubboNamespaceHandler继承Spring提供的NamespaceHandlerSupport来对标签进行解析的

//DubboNamespaceHandler.java
public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }

}

本篇博客主要讲解的是服务提供者的服务暴露过程,也就是<dubbo:service/>标签,那么我们就只需要关心newDubboBeanDefinitionParser(ServiceBean.class,true),ServiceBean的实现即可。

三、ServiceBean

先附上一张ServiceBean架构图。可以看到ServiceBean实现了一系列的Spring生命周期接口来完成服务的暴露、注册、销毁等操作。

我们暂不必关心其它接口的实现,我们更关心的是InitializingBean的实现,因为它包含了我们所要研究的服务提供者暴露过程。

哇哦,这代码还真tm长啊,一会还有更长的.....

  • #1:获取<dubbo:service />的provider属性,如果为空,那么就获取<dubbo:provider/>的实例。(dubbo:provider标签配置的是一些缺省值)

①如果没有配置<dubbo:protocol/>协议,并且,<dubbo:provider/>配置了一个以上,那么会选择provider标签配置了default属性的ProviderConfig

②如果配置了<dubbo:protocol/>协议,如果<dubbo:provider/>配置了一个以上那么会报Duplicate provider configs:异常,否则将会选择一个ProviderConfig。

  • #2获取application属性,如果属性为空,且provider也为空;或者属性为空,provider中application也为空,那么会获取<dubbo:application/>的实例,如果配置了多个<dubbo:application/>标签,则会抛出异常Duplicate application configs:
  • #3获取module属性,和application一样,如果属性为空,且provider也为空;或者属性为空,provider中module也为空那么会获取<dubbo:module/>的实例,如果配置了多个<dubbo:module/>标签,则会抛出异常Duplicate module configs:
  • #4获取registries属性,如果为空,则获取provider中的registries属性,如果也为空,则获取application中的registries属性,如果还为空,那么就去找<dubbo:registry/>标签的实例,dubbo允许配置多个注册中心,将服务注册在不同的注册中心上。
  • #5获取monitor属性,如果为空,则尝试从provider、application中获取,否则,会获取<dubbo:monitor/>标签的实例,monitor可有可无,不过只能配置一个,存在多个会抛出异常Duplicate monitor configs:
  • #6获取protocol属性,如果为空,则获取provider中protocol属性,如果为空,则会获取<dubbo:protocol/>标签的实例,protocol可配置多个,dubbo允许将服务通过不同协议进行暴露。
  • #7延时暴露,如果delay没有设置,或者delay设置为-1将会启用延时加载。是通过实现ApplicationListener接口在SpringIOC初始化完毕后通知ServiceBean完成服务暴露回调,schedule定时任务(单位毫秒)。来实现的。
private boolean isDelay() {
        Integer delay = getDelay();
        ProviderConfig provider = getProvider();
        if (delay == null && provider != null) {
            delay = provider.getDelay();
        }
        return supportedApplicationListener && (delay == null || delay == -1);
    }
 public void onApplicationEvent(ContextRefreshedEvent event) {
        if (isDelay() && !isExported() && !isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + getInterface());
            }
            export();
        }
    }

//ServiceBean->afterPropertiesSet()
    @SuppressWarnings({"unchecked", "deprecation"})
    public void afterPropertiesSet() throws Exception {
        if (getProvider() == null) { #1
            Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
            if (providerConfigMap != null && providerConfigMap.size() > 0) {
                Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
                        && providerConfigMap.size() > 1) { // backward compatibility
                    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() != null && config.isDefault().booleanValue()) {
                            providerConfigs.add(config);
                        }
                    }
                    if (!providerConfigs.isEmpty()) {
                        setProviders(providerConfigs);
                    }
                } else {
                    ProviderConfig providerConfig = null;
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault().booleanValue()) {
                            if (providerConfig != null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
                    if (providerConfig != null) {
                        setProvider(providerConfig);
                    }
                }
            }
        }
        if (getApplication() == null   #2
                && (getProvider() == null || getProvider().getApplication() == null)) {
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
            if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                for (ApplicationConfig config : applicationConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if (applicationConfig != null) {
                            throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                        }
                        applicationConfig = config;
                    }
                }
                if (applicationConfig != null) {
                    setApplication(applicationConfig);
                }
            }
        }
        if (getModule() == null     #3
                && (getProvider() == null || getProvider().getModule() == null)) {
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
            if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                for (ModuleConfig config : moduleConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if (moduleConfig != null) {
                            throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                        }
                        moduleConfig = config;
                    }
                }
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
        if ((getRegistries() == null || getRegistries().isEmpty())  #4
                && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().isEmpty())
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().isEmpty())) {
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false);
            if (registryConfigMap != null && registryConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        registryConfigs.add(config);
                    }
                }
                if (registryConfigs != null && !registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs);
                }
            }
        }
        if (getMonitor() == null    #5
                && (getProvider() == null || getProvider().getMonitor() == null)
                && (getApplication() == null || getApplication().getMonitor() == null)) {
            Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                for (MonitorConfig config : monitorConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        if (monitorConfig != null) {
                            throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                        }
                        monitorConfig = config;
                    }
                }
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
        if ((getProtocols() == null || getProtocols().isEmpty()) #6
                && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().isEmpty())) {
            Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();
                for (ProtocolConfig config : protocolConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        protocolConfigs.add(config);
                    }
                }
                if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
                    super.setProtocols(protocolConfigs);
                }
            }
        }
        if (getPath() == null || getPath().length() == 0) {
            if (beanName != null && beanName.length() > 0
                    && getInterface() != null && getInterface().length() > 0
                    && beanName.startsWith(getInterface())) {
                setPath(beanName);
            }
        }
        if (!isDelay()) {     #7
            export();
        }
    }

接下来分析export()服务暴露方法

  • #1#2如果没有配置export属性和delay属性,则从provider中获取。
  • #3如果export属性为false,那么将不暴露服务,直接返回。
  • #4如果delay不为空 且大于0,将定时执行服务暴露任务。否则直接执行。
//ServiceConfig.java
//ServiceCofnig->export()
public synchronized void export() {
        if (provider != null) {    #1
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {   #2
                delay = provider.getDelay();
            }
        }
        if (export != null && !export) { #3
            return;
        }

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

好吧,doExport()方法依然很长。。。

  • #1如果服务已经暴露,则直接返回。
  • #2<dubbo:service/>中interface配置为空,则抛出异常。
  • #3从参数,或者系统文件中加载属性配置
  • #4前面都是一些属性的填充,很无聊,直接跳过,如果服务ref为genericService或者其子类,那么将会获取generic属性,默认为true。
  • #5否则为普通的接口,加载接口,然后接口方法检查,引用与接口是否匹配。
  • #6stub属性为true,那么会查找接口的Stub类,Stub可以查看这篇博客https://www.cnblogs.com/hzhuxin/p/8250602.html
  • #7进行一系列的属性检查和填充。
  • #8path默认为接口名称例如:dubbo://127.0.0.1:28080/interfaceName.....
//ServiceConfig.java 
//ServiceConfig->doExport()

 protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        if (exported) {  #1
            return;
        }
        exported = true;
        if (interfaceName == null || interfaceName.length() == 0) { #2
            throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
        }
        checkDefault();  #3
        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) { #4
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {   #5
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            checkInterfaceAndMethods(interfaceClass, methods);
            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) {   #6
            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();  #7
        checkRegistry();
        checkProtocol();
        appendProperties(this);
        checkStubAndMock(interfaceClass);
        if (path == null || path.length() == 0) { #8
            path = interfaceName;
        }
        doExportUrls();
        ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
        ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
    }
    

锵锵锵,该doExportUrls()方法了,眼睛酸,下篇博客讲!

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杂烩

组件化项目搭建(非专业,无聊的一次尝试)二 原

        项目建好了,那我们来集成以下dao,dao我们使用mybatis框架,以及druid数据库连接池、oscache缓存,数据库使用mysql 64...

704
来自专栏web开发

java-生成任意格式的json数据

最近研究java的东西。之前靠着自己的摸索,实现了把java对象转成json格式的数据的功能,返回给前端。当时使用的是 JSONObject.fromObjec...

18010
来自专栏余林丰

MyBatis源码解读(1)——SqlSessionFactory

在前面对MyBatis稍微有点了解过后,现在来对MyBatis的源码试着解读一下,并不是解析,暂时定为解读。所有对MyBatis解读均是基于MyBatis-3....

1977
来自专栏JAVA技术站

JFinal整合Spring开发 原

思路大概是这样子的,首先需要初始化Spring的容器,把所有注解类加入到容器中,Spring里的AnnotationConfigApplicationConte...

612
来自专栏余林丰

SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession作用域(Scope)和生命周期

  可以说每个MyBatis都是以一个SqlSessionFactory实例为中心的。SqlSessionFactory实例可以通过SqlSessionFact...

2217
来自专栏Java编程技术

就是让你懂Spring中Mybatis的花样配置

Mybatis作为一个优秀的存储过程和高级映射的持久层框架,目前在项目实践中运用的比较广泛,最近做项目时候发现了一种之前没见过的配置方式,这里总结下常用的配置方...

812
来自专栏函数式编程语言及工具

Akka(33): Http:Marshalling,to Json

  Akka-http是一项系统集成工具。这主要依赖系统之间的数据交换功能。因为程序内数据表达形式与网上传输的数据格式是不相同的,所以需要对程序高级结构化的数据...

26010
来自专栏后端之路

Dubbo超时控制源码分析

我们在么dubbo声明超时大约可以分如下几个层次 上图中以timeout为例,显示了配置的查找顺序,其它retries, loadbalance, active...

4046
来自专栏cmazxiaoma的架构师之路

MyBatis-Spring官方文档 学习笔记

1433
来自专栏web编程技术分享

【Java框架型项目从入门到装逼】第十三节 用户新增功能完结篇

2746

扫码关注云+社区