dubbo源码阅读-服务暴露(七)之主流程

 api方式暴露服务

https://www.cnblogs.com/LQBlog/p/12402704.html#autoid-4-0-0 

// 服务提供者暴露服务配置
ServiceConfig<XxxService> service = new ServiceConfig<XxxService>(); // 此实例很重,封装了与注册中心的连接,请自行缓存,否则可能造成内存和连接泄漏
service.setApplication(application);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(XxxService.class);
service.setRef(xxxService);
service.setVersion("1.0.0");
 
// 暴露及注册服务
service.export();

注解方式

https://www.cnblogs.com/LQBlog/p/12420860.html#autoid-5-5-0

可以发现最终是初始化ServiceBean到spring容器

Xml方式

https://www.cnblogs.com/LQBlog/p/12448988.html#autoid-2-5-0

可以发现也是解析XML初始化ServiceBean到Spring容器

ServiceBean类图

 可以发现ServiceBean实现了InitializingBean 在Spring初始化之后会调用<1>

ServiceBean

<1>afterPropertiesSet

代码过多 也不是核心代码 折叠

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

 public void afterPropertiesSet() throws Exception {
        /**
         * step1
         * dubbo:servie未指定provider
         *     <dubbo:provider id="test1" delay="-1" retries="0" />
         *     <dubbo:service provider="test1" interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl"/>
         */
        if (getProvider() == null) {
            /**
             * step2
             *  BeanFactoryUtils.beansOfTypeIncludingAncestors为获取指定类型以及实现类和子类的集合 key为name
             */
            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
                && (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
                && (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())
                && (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
                && (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())
                && (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);
            }
        }
        //上面都是加载Config 是否配置了延迟加载
        if (!isDelay()) {
            //<2>服务发布
            export();
        }
    }
View Code

<2>export

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

   @Override
    public void export() {
        //<3>调用父类com.alibaba.dubbo.config.ServiceConfig.export
        //可以发现这里就是api配置调用的export
        super.export();
        /**
         *  ReferenceAnnotationBeanPostProcessor消费
         *  也可以自定义实现ApplicationListener<ServiceBeanExportedEvent> 封装了ServiceBean的信息
         */
        publishExportEvent();
    }

ServiceConfig

<3>export

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

->

com.alibaba.dubbo.config.ServiceConfig#export

public synchronized void export() {
        //获取export配置 如果未配置则取provider 作用是是否发布服务
        if (provider != null) {
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {
                //delay会默认从service配置上取 如果没有配置则获取providerConfig的配置
                delay = provider.getDelay();
            }
        }
        //如果配置false则不会发布服务,
        if (export != null && !export) {
            return;
        }
        //如果配置了延迟加载
        if (delay != null && delay > 0) {
            //秒为单位延迟多少秒暴露服务
            delayExportExecutor.schedule(new Runnable() {
                @Override
                public void run() {
                    //<4>
                    doExport();
                }
            }, delay, TimeUnit.MILLISECONDS);
        } else {
            //<4>未配置延迟加载直接暴露
            doExport();
        }
    }

<4>doExport

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

->

com.alibaba.dubbo.config.ServiceConfig#export

->

com.alibaba.dubbo.config.ServiceConfig#doExport

    protected synchronized void doExport() {
        //unexport()如果调用了下线方法 则不能再发布
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        //已经发布 则不能再发布
        if (exported) {
            return;
        }
        //改为true
        exported = true;
        //没有配置接口全名称
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:service interface="" /> interface not allow null!");
        }
        //缺省值配置 系统变量>properties配置>最终找不到部分配置根据映射再获取
        checkDefault();
        //如果未配置provider、application、module、protocols 则从providerConfig获取获取
        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();
            }
        }
        //如果未配置registries、monitor 则从moduleConfig获取
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        //如果未配置registries,monitor 则从application 获取
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        /**
         * 是否是泛型化暴露服务 可以查看具体文档
         * http://dubbo.apache.org/zh-cn/docs/user/demos/generic-service.html
         */
        if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                //标识为泛型化
                generic = Boolean.TRUE.toString();
            }
        } else {
            //获取配置的interfaceName的calas
            try {
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            //<30>检查methods配置在接口中是否存在 配置文档http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-method.html
            checkInterfaceAndMethods(interfaceClass, methods);
            //检查配置的ref对象 是否是配置的接口的实现
            checkRef();
            //非泛型化暴露
            generic = Boolean.FALSE.toString();
        }
        //是否是本地发布 本地存根 用于调用接口前做一些逻辑 代理
        if (local != null) {
            if ("true".equals(local)) {
                local = interfaceName + "Local";
            }
            Class<?> localClass;
            try {
                //反射获取配置的接口机上Local后置的实现类
                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);
            }
        }
        //loca的替代  是否是本地发布 本地存根 用于调用接口前做一些逻辑 代理
        if (stub != null) {
            if ("true".equals(stub)) {
                stub = interfaceName + "Stub";
            }
            Class<?> stubClass;
            try {
                //反射获取配置的接口机上Stub后置的实现类
                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);
            }
        }
        //<5>检查application配置
        checkApplication();
        //<6>检查registry配置
        checkRegistry();
        //<7>检查protocol配置
        checkProtocol();
        //<8>系统变量>properties配置>最终找不到部分配置根据映射再获取
        appendProperties(this);
        //<9>检查local或者stub 本地存根 是否有配置一个当前接口类型参数的构造函数
        checkStub(interfaceClass);
        //<10>降级 和local或者 stub一样 检查mock配置
        checkMock(interfaceClass);
        //没有配置path则设置接口名字
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
        //<11>配置准备就绪 暴露服务 并注册 com.alibaba.dubbo.config.ServiceConfig.doExportUrls
        doExportUrls();
        //放置到已发布队列
        ProviderModel providerModel = new ProviderModel(getUniqueServiceName(), this, ref);
        ApplicationModel.initProviderModel(getUniqueServiceName(), providerModel);
    }

<30>checkInterfaceAndMethods

com.alibaba.dubbo.config.AbstractInterfaceConfig#checkInterfaceAndMethods

    protected void checkInterfaceAndMethods(Class<?> interfaceClass, List<MethodConfig> methods) {
        // interface cannot be null
        if (interfaceClass == null) {
            throw new IllegalStateException("interface not allow null!");
        }
        // to verify interfaceClass is an interface
        if (!interfaceClass.isInterface()) {
            throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!");
        }
        // 如果配置了methodConfig
        if (methods != null && !methods.isEmpty()) {
            for (MethodConfig methodBean : methods) {
                //获取name
                String methodName = methodBean.getName();
                //如果为配置的抛错
                if (methodName == null || methodName.length() == 0) {
                    throw new IllegalStateException("<dubbo:method> name attribute is required! Please check: <dubbo:service interface="" + interfaceClass.getName() + "" ... ><dubbo:method name="" ... /></<dubbo:reference>");
                }
                boolean hasMethod = false;
                //反射检查是否当前config有此method  文档:http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-method.html
                for (java.lang.reflect.Method method : interfaceClass.getMethods()) {
                    if (method.getName().equals(methodName)) {
                        hasMethod = true;
                        break;
                    }
                }
                //如果配置了没有则报错
                if (!hasMethod) {
                    throw new IllegalStateException("The interface " + interfaceClass.getName()
                            + " not found method " + methodName);
                }
            }
        }
    }

<5>checkApplication

com.alibaba.dubbo.config.AbstractInterfaceConfig#checkApplication

protected void checkApplication() {
        // 如果配有配置application
        if (application == null) {
            //从属性配置获取dubbo.application.name 配置
            String applicationName = ConfigUtils.getProperty("dubbo.application.name");
            if (applicationName != null && applicationName.length() > 0) {
                //如果有配置则初始化一个config
                application = new ApplicationConfig();
            }
        }
        //<8>表示没有配置application报错
        if (application == null) {
            throw new IllegalStateException(
                    "No such application config! Please add <dubbo:application name="..." /> to your spring config.");
        }
        //进行初始化这里可以发现优先级 系统变量>properties配置>最终找不到部分配置根据映射再获取
        appendProperties(application);

        //获取properties变量keydubbo.service.shutdown.wait 配置 用于优雅停机等待时间
        String wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_KEY);
        if (wait != null && wait.trim().length() > 0) {
            //清除左右空格seet到系统变量
            System.setProperty(Constants.SHUTDOWN_WAIT_KEY, wait.trim());
        } else {
            //尝试从 key:dubbo.service.shutdown.wait.seconds获取 已经废弃主要兼容老配置 应用于优雅停机等待时间
            wait = ConfigUtils.getProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY);
            if (wait != null && wait.trim().length() > 0) {
                //seet进去
                System.setProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY, wait.trim());
            }
        }
    }

<6>checkRegistry

com.alibaba.dubbo.config.AbstractInterfaceConfig#checkRegistry

 protected void checkRegistry() {
        // for backward compatibility
        //检查是否有registry配置 如果没有则尝试读取properties文件获取dubbo.registry.address 配置
        if (registries == null || registries.isEmpty()) {
            String address = ConfigUtils.getProperty("dubbo.registry.address");
            if (address != null && address.length() > 0) {
                registries = new ArrayList<RegistryConfig>();
                String[] as = address.split("\s*[|]+\s*");
                for (String a : as) {
                    RegistryConfig registryConfig = new RegistryConfig();
                    registryConfig.setAddress(a);
                    registries.add(registryConfig);
                }
            }
        }
        //未配置报错
        if ((registries == null || registries.isEmpty())) {
            throw new IllegalStateException((getClass().getSimpleName().startsWith("Reference")
                    ? "No such any registry to refer service in consumer "
                    : "No such any registry to export service in provider ")
                    + NetUtils.getLocalHost()
                    + " use dubbo version "
                    + Version.getVersion()
                    + ", Please add <dubbo:registry address="..." /> to your spring config. If you want unregister, please set <dubbo:service registry="N/A" />");
        }
        for (RegistryConfig registryConfig : registries) {
            //<8>
            appendProperties(registryConfig);
        }
    }

<7>checkProtocol

com.alibaba.dubbo.config.ServiceConfig#checkProtocol

 private void checkProtocol() {
        if ((protocols == null || protocols.isEmpty())
                && provider != null) {
            setProtocols(provider.getProtocols());
        }
        // backward compatibility
        if (protocols == null || protocols.isEmpty()) {
            setProtocol(new ProtocolConfig());
        }
        for (ProtocolConfig protocolConfig : protocols) {
            if (StringUtils.isEmpty(protocolConfig.getName())) {
                protocolConfig.setName(Constants.DUBBO_VERSION_KEY);
            }
            appendProperties(protocolConfig);
        }
    }

<8>appendProperties

com.alibaba.dubbo.config.AbstractConfig#appendProperties

   /**
     * 这里可以发现优先级 系统变量>properties配置>最终找不到部分配置根据映射再获取
     * @param config
     */
    protected static void appendProperties(AbstractConfig config) {
        if (config == null) {
            return;
        }
        //获取前缀 比如ProviderConfig=dubbo.provider.  ServiceBean=dubbo.service
        String prefix = "dubbo." + getTagName(config.getClass()) + ".";
        //反射获取当前class的所有method元数据
        Method[] methods = config.getClass().getMethods();
        for (Method method : methods) {
            try {
                String name = method.getName();
                //长度大于3同时是set开头 同时入参只有一个isPrimitive判断是基本类型
                if (name.length() > 3 && name.startsWith("set") && Modifier.isPublic(method.getModifiers())
                        && method.getParameterTypes().length == 1 && isPrimitive(method.getParameterTypes()[0])) {
                    //截取方法名字除丢弃set 比如setExport=export.
                    String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), ".");

                    String value = null;
                    //如果config含有id
                    if (config.getId() != null && config.getId().length() > 0) {
                        //如 dubbo.application.id1.export
                        String pn = prefix + config.getId() + "." + property;
                        //获取系统参数 如-Ddubbo.application.id1.export=true
                        value = System.getProperty(pn);
                        if (!StringUtils.isBlank(value)) {
                            logger.info("Use System Property " + pn + " to config dubbo");
                        }
                    }
                    //如果未获取到 则丢弃id直接获取 比如-Ddubbo.application.export 获取全局配置
                    if (value == null || value.length() == 0) {
                        String pn = prefix + property;
                        value = System.getProperty(pn);
                        if (!StringUtils.isBlank(value)) {
                            logger.info("Use System Property " + pn + " to config dubbo");
                        }
                    }
                    //上面2步仍未获取到
                    if (value == null || value.length() == 0) {
                        Method getter;
                        try {
                            //获取get方法
                            getter = config.getClass().getMethod("get" + name.substring(3));
                        } catch (NoSuchMethodException e) {
                            try {
                                //避免是boolean类型 get方法是is
                                getter = config.getClass().getMethod("is" + name.substring(3));
                            } catch (NoSuchMethodException e2) {
                                getter = null;
                            }
                        }
                        if (getter != null) {
                            //反射调用get方法 判断是否存是空
                            if (getter.invoke(config) == null) {
                                //开始从properties文件获取
                                if (config.getId() != null && config.getId().length() > 0) {
                                    value = ConfigUtils.getProperty(prefix + config.getId() + "." + property);
                                }
                                if (value == null || value.length() == 0) {
                                    value = ConfigUtils.getProperty(prefix + property);
                                }
                                //如果仍未获取到
                                if (value == null || value.length() == 0) {
                                    //获取映射key 具体看static初始化
                                    String legacyKey = legacyProperties.get(prefix + property);
                                    if (legacyKey != null && legacyKey.length() > 0) {
                                        //根据映射key再到propertis获取 convert只是对部分key做兼容处理
                                        value = convertLegacyValue(legacyKey, ConfigUtils.getProperty(legacyKey));
                                    }
                                }

                            }
                        }
                    }
                    //如果读取到反射注入
                    if (value != null && value.length() > 0) {
                        method.invoke(config, convertPrimitive(method.getParameterTypes()[0], value));
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
    }

<9>checkStub

com.alibaba.dubbo.config.AbstractInterfaceConfig#checkStub

void checkStub(Class<?> interfaceClass) {
        //如果是配置了local  用于调用前的代理 接口名字+Local是否含有一个 当前接口类型的构造函数
        if (ConfigUtils.isNotEmpty(local)) {
            Class<?> localClass = ConfigUtils.isDefault(local) ? ReflectUtils.forName(interfaceClass.getName() + "Local") : ReflectUtils.forName(local);
            if (!interfaceClass.isAssignableFrom(localClass)) {
                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName());
            }
            try {
                ReflectUtils.findConstructor(localClass, interfaceClass);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("No such constructor "public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")" in local implementation class " + localClass.getName());
            }
        }
        //如果是配置了stub  用于调用前的代理  则判断容错实现类 接口名字+Local是否含有一个 当前接口类型的构造函数
        if (ConfigUtils.isNotEmpty(stub)) {
            Class<?> localClass = ConfigUtils.isDefault(stub) ? ReflectUtils.forName(interfaceClass.getName() + "Stub") : ReflectUtils.forName(stub);
            if (!interfaceClass.isAssignableFrom(localClass)) {
                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceClass.getName());
            }
            try {
                ReflectUtils.findConstructor(localClass, interfaceClass);
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("No such constructor "public " + localClass.getSimpleName() + "(" + interfaceClass.getName() + ")" in local implementation class " + localClass.getName());
            }
        }
    }

<10>checkMock

com.alibaba.dubbo.config.AbstractInterfaceConfig#checkMock

    void checkMock(Class<?> interfaceClass) {
        if (ConfigUtils.isEmpty(mock)) {
            return;
        }

        //将mock配置做转换
        String normalizedMock = MockInvoker.normalizeMock(mock);
        if (normalizedMock.startsWith(Constants.RETURN_PREFIX)) {
            //主要mock配置的值是否是有效的值 比如配置的json 是否是有效json 出现异常返回结果
            normalizedMock = normalizedMock.substring(Constants.RETURN_PREFIX.length()).trim();
            try {
                MockInvoker.parseMockValue(normalizedMock);
            } catch (Exception e) {
                throw new IllegalStateException("Illegal mock return in <dubbo:service/reference ... " +
                        "mock="" + mock + "" />");
            }
            //这里主要检查mock配置的 出现异常抛出的异常是是有效 因为出现异常后 将抛出配置的异常
        } else if (normalizedMock.startsWith(Constants.THROW_PREFIX)) {
            normalizedMock = normalizedMock.substring(Constants.THROW_PREFIX.length()).trim();
            if (ConfigUtils.isNotEmpty(normalizedMock)) {
                try {
                    MockInvoker.getThrowable(normalizedMock);
                } catch (Exception e) {
                    throw new IllegalStateException("Illegal mock throw in <dubbo:service/reference ... " +
                            "mock="" + mock + "" />");
                }
            }
        } else {
            //这里检查配置的mock类是否是有效类 如果配置的是default则默认是default 接口名字+Mock
            MockInvoker.getMockObject(normalizedMock, interfaceClass);
        }
    }

<11>doExportUrls

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

->

com.alibaba.dubbo.config.ServiceConfig#export

->

com.alibaba.dubbo.config.ServiceConfig#doExport

->

com.alibaba.dubbo.config.ServiceConfig#doExportUrls

 private void doExportUrls() {
        //// <12>加载注册中心 URL 数组
        List<URL> registryURLs = loadRegistries(true);
        //// 循环 `protocols` ,向逐个注册中心分组暴露服务。
        for (ProtocolConfig protocolConfig : protocols) {
            //<13>
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

<12>loadRegistries

com.alibaba.dubbo.config.AbstractInterfaceConfig#loadRegistries

protected List<URL> loadRegistries(boolean provider) {
        //<6>检查并加载注册中心配置
        checkRegistry();
        List<URL> registryList = new ArrayList<URL>();
        if (registries != null && !registries.isEmpty()) {
            for (RegistryConfig config : registries) {
                String address = config.getAddress();
                //未配置地址 则取0.0.0.0
                if (address == null || address.length() == 0) {
                    address = Constants.ANYHOST_VALUE;
                }
                //如果配置了系统变量 则通过系统变量覆盖
                String sysaddress = System.getProperty("dubbo.registry.address");
                if (sysaddress != null && sysaddress.length() > 0) {
                    address = sysaddress;
                }
                //如果地址不等于N/A
                if (address.length() > 0 && !RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(address)) {
                    Map<String, String> map = new HashMap<String, String>();
                    //反射获取application所有公共的get方法 以及parameter配置 封装到map
                    appendParameters(map, application);
                    //反射获取config所有公共方法并封装到map
                    appendParameters(map, config);
                    //设置path到map
                    map.put("path", RegistryService.class.getName());
                    //设置dubbo版本
                    map.put("dubbo", Version.getProtocolVersion());
                    //设置时间
                    map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
                    //获取线程进程
                    if (ConfigUtils.getPid() > 0) {
                        //将进程id设置到map
                        map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
                    }
                    if (!map.containsKey("protocol")) {
                        //主要是获取是否有key为remote的SPI扩展
                        if (ExtensionLoader.getExtensionLoader(RegistryFactory.class).hasExtension("remote")) {
                            map.put("protocol", "remote");
                        } else {
                            //如果没有则协议dubbo协议
                            map.put("protocol", "dubbo");
                        }
                    }
                    //封装注册中心地址 以及参数map到url
                    List<URL> urls = UrlUtils.parseURLs(address, map);
                    for (URL url : urls) {
                        //url增加registry=协议
                        url = url.addParameter(Constants.REGISTRY_KEY, url.getProtocol());
                        //url设置协议为registry
                        url = url.setProtocol(Constants.REGISTRY_PROTOCOL);
                        //如果是服务注册同时协议是registry则增加到注册url
                        if ((provider && url.getParameter(Constants.REGISTER_KEY, true))
                                || (!provider && url.getParameter(Constants.SUBSCRIBE_KEY, true))) {
                            registryList.add(url);
                        }
                    }
                }
            }
        }
        return registryList;
    }

<13>doExportUrlsFor1Protocol

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

->

com.alibaba.dubbo.config.ServiceConfig#export

->

com.alibaba.dubbo.config.ServiceConfig#doExport

->

com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        //获取协议名
        String name = protocolConfig.getName();
        //如果没配置 则默认dubbo
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }

        Map<String, String> map = new HashMap<String, String>();
        //封装 sid=provider 到map
        map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
        //设置dubbo版本
        map.put(Constants.DUBBO_VERSION_KEY, Version.getProtocolVersion());
        //设置时间
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
        //<6>反射获取application所有公共的get方法 以及parameter配置 封装到map
        appendParameters(map, application);
        //<6>反射获取moule所有公共的get方法 以及parameter配置 封装到map
        appendParameters(map, module);
        //<6>反射获取provider所有公共的get方法 以及parameter配置 封装到map
        appendParameters(map, provider, Constants.DEFAULT_KEY);
        //<6>反射获取provider所有公共的get方法 以及parameter配置 封装到map
        appendParameters(map, protocolConfig);
        //<6>反射获取当前Service所有公共的get方法 以及parameter配置 封装到map
        appendParameters(map, this);
        //封装methodConfig配置到map
        if (methods != null && !methods.isEmpty()) {
            ....//胜率部分代码
        }

        //是否为泛型化发布
        if (ProtocolUtils.isGeneric(generic)) {
            //增加参数generic=true
            map.put(Constants.GENERIC_KEY, generic);
            //增加methods=*
            map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
        } else {
            //这种版本号到map
            String revision = Version.getVersion(interfaceClass, version);
            if (revision != null && revision.length() > 0) {
                map.put("revision", revision);
            }

            String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("NO method found in service interface " + interfaceClass.getName());
                map.put(Constants.METHODS_KEY, Constants.ANY_VALUE);
            } else {
                //主要是将暴露方法封装到map
                map.put(Constants.METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        //是否有token配置 将token配置到map
        if (!ConfigUtils.isEmpty(token)) {
            if (ConfigUtils.isDefault(token)) {
                map.put(Constants.TOKEN_KEY, UUID.randomUUID().toString());
            } else {
                map.put(Constants.TOKEN_KEY, token);
            }
        }
        //获取协议是否是本地调用injvm
        if (Constants.LOCAL_PROTOCOL.equals(protocolConfig.getName())) {
            //配置不注册
            protocolConfig.setRegister(false);
            //map增加参数notify=false
            map.put("notify", "false");
        }
        // 如果protocolConfig 没有配置contextPath则从provider获取
        String contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }
        /**
         * <14>获取暴露服务的host
         */
        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        //<15>暴露服务的port
        Integer port = this.findConfigedPorts(protocolConfig, name, map);
        //组织暴露的url
        URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);


        //SPI扩展点根据协议判断是否有指定协议Protocol的ConfiguratorFactory 扩展 可以覆盖我们的Url
        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }


        /**
         * 构建invoker实例
         * 获取dubbo:service配置的scope属性
         * 其可选值为 none (不暴露)、local (本地)、remote (远程),如果配置为 none,则不暴露。默认为 local。
         */
        String scope = url.getParameter(Constants.SCOPE_KEY);
        // don't export when none is configured SCOPE_NONE!=none如果未配置none
        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            // export to local if the config is not remote (export to remote only when config is remote)
            //remote!=scope  什么是本地暴露: https://zhuanlan.zhihu.com/p/98423741
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                //<16>本地暴露
                exportLocal(url);
            }
            // 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) {
                        //是否配置了动态注册dynamic 作用看文档注释 http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-service.html
                        url = url.addParameterIfAbsent(Constants.DYNAMIC_KEY, registryURL.getParameter(Constants.DYNAMIC_KEY));
                        //获取监控地址url monitor配置
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            //将监控地址追加到url
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }

                        // For providers, this is used to enable custom proxy to generate invoker
                        //是否有配置proxy 生成动态代理的方式 如果有追加到registryURL参数 见文档http://dubbo.apache.org/zh-cn/docs/user/references/xml/dubbo-service.html
                        String proxy = url.getParameter(Constants.PROXY_KEY);
                        if (StringUtils.isNotEmpty(proxy)) {
                            registryURL = registryURL.addParameter(Constants.PROXY_KEY, proxy);
                        }
                        /**
                         *     private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
                         *     spi扩展点 生成Invoker
                         *     invoker封装了代理类也就是我们的ServiceImpl类 以及url信息
                         *     registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())
                         *     在registryUrl 追加export=暴露的url
                         *     invoker的url是regitry 参数加了export八路url
                         */
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
                        //增强 代理了invoker 封装了serviceConfig信息
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        //<17>注意 invoker的url是registryUrl 所以protocol=registry SPI调用的是
                        //registry=com.alibaba.dubbo.registry.integration.RegistryProtocol  直通车:https://www.cnblogs.com/LQBlog/p/12470681.html
                        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);
    }

<14>findConfigedHosts

private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
        boolean anyhost = false;

        //尝试通过protocolConfig的name_DUBBO_IP_TO_BIND或者DUBBO_IP_TO_BIND 获取绑定ip配置
        String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND);
        //如果配置了验证是否是有效ip
        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 bind ip is not found in environment, keep looking up
        if (hostToBind == null || hostToBind.length() == 0) {
            //尝试偶从protocol获取
            hostToBind = protocolConfig.getHost();
            //尝试从 providerConfig获取
            if (provider != null && (hostToBind == null || hostToBind.length() == 0)) {
                hostToBind = provider.getHost();
            }
            //如果配置了验证是否不是有效ip
            if (isInvalidLocalHost(hostToBind)) {
                anyhost = true;
                try {
                    //如果没有配置则 从本机获取
                    hostToBind = InetAddress.getLocalHost().getHostAddress();
                } catch (UnknownHostException e) {
                    logger.warn(e.getMessage(), e);
                }
                //验证是否不是有效ip
                if (isInvalidLocalHost(hostToBind)) {
                    if (registryURLs != null && !registryURLs.isEmpty()) {
                        for (URL registryURL : registryURLs) {
                            //是否配置了registry=multicast 广播模式 本地广播模式
                            if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
                                // skip multicast registry since we cannot connect to it via Socket
                                continue;
                            }
                            try {
                                Socket socket = new Socket();
                                try {
                                    //以上方式都获取不到ip则尝试跟各个注册中心建立soket连接再根据socketapi获取绑定ip
                                    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)) {
                        //尝试使用java NetworkInterface api绑定端口
                        hostToBind = getLocalHost();
                    }
                }
            }
        }

        //将绑定ip追加map
        map.put(Constants.BIND_IP_KEY, hostToBind);

        // registry ip is not used for bind ip by default  是否配置DUBBO_IP_TO_REGISTRY 如果有配置通过他来替代暴露地址
        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) {
            // bind ip is used as registry ip by default  如果未配置DUBBO_IP_TO_REGISTRY则还是取hostToBind
            hostToRegistry = hostToBind;
        }

        //map增加anyhost
        map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost));

        return hostToRegistry;
    }

<15>findConfigedPorts

    private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
        Integer portToBind = null;

        // parse bind port from environment 从DUBBO_PORT_TO_BIND配置获取
        String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
        //验证是否是有效port
        portToBind = parsePort(port);

        // if there's no bind port found from environment, keep looking up.
        if (portToBind == null) {
            //从protocolConfig获取
            portToBind = protocolConfig.getPort();
            if (provider != null && (portToBind == null || portToBind == 0)) {
                //如果protocolConfig无效则通过provider获取
                portToBind = provider.getPort();
            }
            //获取SPI扩展类 的defaultPort属性值
            final int defaultPort = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name).getDefaultPort();
            if (portToBind == null || portToBind == 0) {
                portToBind = defaultPort;
            }
            //如果未配置则随机生成
            if (portToBind == null || portToBind <= 0) {
                portToBind = getRandomPort(name);
                if (portToBind == null || portToBind < 0) {
                    portToBind = getAvailablePort(defaultPort);
                    //
                    putRandomPort(name, portToBind);
                }
                logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
            }
        }

        // save bind port, used as url's key later
        map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));

        // registry port, not used as bind port by default
        String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
        Integer portToRegistry = parsePort(portToRegistryStr);
        if (portToRegistry == null) {
            portToRegistry = portToBind;
        }

        return portToRegistry;
    }

<16>exportLocal

com.alibaba.dubbo.config.spring.ServiceBean#afterPropertiesSet

->

com.alibaba.dubbo.config.spring.ServiceBean#export

->

com.alibaba.dubbo.config.ServiceConfig#export

->

com.alibaba.dubbo.config.ServiceConfig#doExport

->

com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol

->

com.alibaba.dubbo.config.ServiceConfig#exportLocal

  private void exportLocal(URL url) {
        //如果协议为不是injvm
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            //生成本地Url
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)//injvm
                    .setHost(LOCALHOST) //127.0.0.1
                    .setPort(0);
            //service.classimpl 将本地暴露接口存入StaticContext map key为接口 value为实现类的名字
            StaticContext.getContext(Constants.SERVICE_IMPL_CLASS).put(url.getServiceKey(), getServiceClass(ref));
            /**
             * 使用 ProxyFactory 创建 Invoker 对象 根据url配置的proxy来作为spi的Key 缺省值是javasist 动态生成一个代理class 也可以使用jdk
             * private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
             * 使用 Protocol 暴露 Invoker 对象 根据url的protcol 来作为SPIKey查找 缺省值duboo
             *
             * private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
* 直通车:https://www.cnblogs.com/LQBlog/p/12470179.html
*/ Exporter<?> exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); // 添加到 `exporters` exporters.add(exporter); logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry"); } }

走到这里就是分水岭了 采用什么样的协议暴露服务

原文地址:https://www.cnblogs.com/LQBlog/p/12469007.html