zoukankan      html  css  js  c++  java
  • 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"); } }

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

  • 相关阅读:
    Windows下PHP开启mcrypt扩展和SSL(OpenSSL)扩展支持
    MyBatis 学习笔记
    试用百度云计算平台
    TCP三次握手及四次挥手详细图解
    Java开发中的23种设计模式详解
    Extjs4.1.0_从入门到精通
    SQLite3命令操作大全
    带你了解 HBase 数据模型和 HBase 架构
    让数据库无惧灾难,华为云GaussDB同城双集群高可用方案正式发布!
    论文阅读丨神经清洁: 神经网络中的后门攻击识别与缓解
  • 原文地址:https://www.cnblogs.com/LQBlog/p/12469007.html
Copyright © 2011-2022 走看看