原理

dubbo根据spring 2.0的schma实现 解析xml并初始化相关bean 初始化dubbo:service为ServiceBean实例  通过spring的生命周期相应回调实现服务发布

ServiceBean源码

import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.AbstractApplicationContext;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * InitializingBean
 *  1.初始化的时候会调用afterPropertiesSet方法
 *  2.优先级高于init-method
 *  3.如果afterPropertiesSet出现异常 则不调用init-method
 * DisposableBean
 *  1.当调用context.close的时候会执行destroy
 * ApplicationContextAware
 *  1.初始化对象会传入spring上下文容器
 * ApplicationListener事件
 *  1.ContextRefreshedEvent
 *     ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。
 *     此处的初始化是指:所有的Bean被成功装载,后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用
 *  2.ContextStartedEvent
 *    当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。
 *    你可以调查你的数据库,或者你可以在接受到这个事件后重启任何停止的应用程序
 *  3.ContextStoppedEvent
 *    当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时,发布这个事件。你可以在接受到这个事件后做必要的清理的工作
 *  4.ContextClosedEvent
 *    当使用 ConfigurableApplicationContext 接口中的 close() 方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端;它不能被刷新或重启
 *  5.RequestHandledEvent
 *    这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。
 *    在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件
 * @param <T>
 */
  class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {

    /**
     * ApplicationContextAware接口实现方法
     * @param applicationContext
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
        if (applicationContext != null) {
            SPRING_CONTEXT = applicationContext;

            try {
                Method method = applicationContext.getClass().getMethod("addApplicationListener", ApplicationListener.class);
                method.invoke(applicationContext, this);
                this.supportedApplicationListener = true;
            } catch (Throwable var5) {
                if (applicationContext instanceof AbstractApplicationContext) {
                    try {
                        Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", ApplicationListener.class);
                        if (!method.isAccessible()) {
                            method.setAccessible(true);
                        }

                        method.invoke(applicationContext, this);
                        this.supportedApplicationListener = true;
                    } catch (Throwable var4) {
                        ;
                    }
                }
            }
        }

    }

    /**
     * BeanNameAware 接口实现方法
     * @param name
     */
    public void setBeanName(String name) {
        this.beanName = name;
    }

    /**
     * ApplicationListener实现方法
     * ContextRefreshedEvent bean被装载则会调用
     * @param event
     */
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (this.isDelay() && !this.isExported() && !this.isUnexported()) {
            if (logger.isInfoEnabled()) {
                logger.info("The service ready on spring started. service: " + this.getInterface());
            }

            this.export();
        }

    }

    /**
     * InitializingBean
     * 实现方法
     * @throws Exception
     */

    public void afterPropertiesSet() throws Exception {
        Map providerConfigMap;
        /**
         * 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 (this.getProvider() == null) {
            /**
             * step2
             *  BeanFactoryUtils.beansOfTypeIncludingAncestors为获取指定类型以及实现类和子类的集合 key为name
             */
            providerConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProviderConfig.class, false, false);
            /**
             * 这里面代码逻辑是混乱的 主要看下面分支吧
             */
            if (providerConfigMap != null && providerConfigMap.size() > 0) {
               Map<String, ProtocolConfig> protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class, false, false);
                Iterator i$;
                ProviderConfig config;
                /**

                 */
                if ((protocolConfigMap == null || protocolConfigMap.size() == 0) && protocolConfigMap.size() > 1) {
                    List<ProviderConfig> providerConfigs = new ArrayList();
                    i$ = protocolConfigMap.values().iterator();

                    while(i$.hasNext()) {
                        config = (ProviderConfig)i$.next();
                        if (config.isDefault() != null && config.isDefault()) {
                            providerConfigs.add(config);
                        }
                    }

                    if (!providerConfigs.isEmpty()) {
                        this.setProviders(providerConfigs);
                    }
                } else {

                    ProviderConfig providerConfig = null;
                    i$ = protocolConfigMap.values().iterator();
                    label318:
                    /**
                     * step4
                     * 这里面需要注意 要么default为true的放到第一个  要么 非default设置为false 没有缺省值 会报Duplicate provider configs
                     * <dubbo:provider id="test1"  delay="-1" retries="0" />
                     *  <dubbo:provider id="test2" default="true" delay="-1" retries="0" />
                     */
                    while(true) {
                        do {
                            if (!i$.hasNext()) {
                                if (providerConfig != null) {
                                    this.setProvider(providerConfig);
                                }
                                break label318;
                            }

                            config = (ProviderConfig)i$.next();
                            //以上面数据为列 默认null 结束循环  whlie(true) 第二次进来providerConfig不为空 就会报duplicate异常
                        } while(config.isDefault() != null && !config.isDefault());

                        if (providerConfig != null) {
                            throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                        }

                        providerConfig = config;
                    }
                }
            }
        }

        Iterator i$;
        /**
         * 跟上面逻辑一样 只是是读取application标签
         *  <dubbo:application name="soa-promotion-provider"/>
         */
        if (this.getApplication() == null && (this.getProvider() == null || this.getProvider().getApplication() == null)) {
            protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ApplicationConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                i$ = protocolConfigMap.values().iterator();

                label291:
                while(true) {
                    ApplicationConfig config;
                    do {
                        if (!i$.hasNext()) {
                            if (applicationConfig != null) {
                                this.setApplication(applicationConfig);
                            }
                            break label291;
                        }

                        config = (ApplicationConfig)i$.next();
                    } while(config.isDefault() != null && !config.isDefault());

                    if (applicationConfig != null) {
                        throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                    }

                    applicationConfig = config;
                }
            }
        }

        /**
         * 跟上面一样 读取moudule标签
         * <dubbo:module name="soa-promotion-provider" version="1.0" owner="liqianng" organization="信息部"></dubbo:module>
         */
        if (this.getModule() == null && (this.getProvider() == null || this.getProvider().getModule() == null)) {
            protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ModuleConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                i$ = protocolConfigMap.values().iterator();

                label270:
                while(true) {
                    ModuleConfig config;
                    do {
                        if (!i$.hasNext()) {
                            if (moduleConfig != null) {
                                this.setModule(moduleConfig);
                            }
                            break label270;
                        }

                        config = (ModuleConfig)i$.next();
                    } while(config.isDefault() != null && !config.isDefault());

                    if (moduleConfig != null) {
                        throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                    }

                    moduleConfig = config;
                }
            }
        }

        ArrayList protocolConfigs;
        /**
         * 同上
         *  <dubbo:registry address="${zookeeper.url}"   file=".dubbo/promotion-provider.cache" check="false" />
         */
        if ((this.getRegistries() == null || this.getRegistries().isEmpty()) && (this.getProvider() == null || this.getProvider().getRegistries() == null || this.getProvider().getRegistries().isEmpty()) && (this.getApplication() == null || this.getApplication().getRegistries() == null || this.getApplication().getRegistries().isEmpty())) {
            protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, RegistryConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                protocolConfigs = new ArrayList();
                i$ = protocolConfigMap.values().iterator();

                label240:
                while(true) {
                    RegistryConfig config;
                    do {
                        if (!i$.hasNext()) {
                            if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
                                super.setRegistries(protocolConfigs);
                            }
                            break label240;
                        }

                        config = (RegistryConfig)i$.next();
                    } while(config.isDefault() != null && !config.isDefault());

                    protocolConfigs.add(config);
                }
            }
        }

        /**
         *  //表示从注册中心发现监控地址
         *     <dubbo:monitor protocol="registry"></dubbo:monitor>
         */
        if (this.getMonitor() == null && (this.getProvider() == null || this.getProvider().getMonitor() == null) && (this.getApplication() == null || this.getApplication().getMonitor() == null)) {
            protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MonitorConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                i$ = protocolConfigMap.values().iterator();

                label215:
                while(true) {
                    MonitorConfig config;
                    do {
                        if (!i$.hasNext()) {
                            if (monitorConfig != null) {
                                this.setMonitor(monitorConfig);
                            }
                            break label215;
                        }

                        config = (MonitorConfig)i$.next();
                    } while(config.isDefault() != null && !config.isDefault());

                    if (monitorConfig != null) {
                        throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                    }

                    monitorConfig = config;
                }
            }
        }
        /**
         * 获取配置的协议信息
         *   <dubbo:protocol register="false"  name="dubbo" port="23888" threadpool="fixed" threads="500" dispatcher="message"/>
         *
         */
        if ((this.getProtocols() == null || this.getProtocols().isEmpty()) && (this.getProvider() == null || this.getProvider().getProtocols() == null || this.getProvider().getProtocols().isEmpty())) {
            protocolConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class, false, false);
            if (protocolConfigMap != null && protocolConfigMap.size() > 0) {
                protocolConfigs = new ArrayList();
                i$ = protocolConfigMap.values().iterator();

                label190:
                while(true) {
                    ProtocolConfig config;
                    do {
                        if (!i$.hasNext()) {
                            if (protocolConfigs != null && !protocolConfigs.isEmpty()) {
                                super.setProtocols(protocolConfigs);
                            }
                            break label190;
                        }

                        config = (ProtocolConfig)i$.next();
                    } while(config.isDefault() != null && !config.isDefault());

                    protocolConfigs.add(config);
                }
            }
        }

        if ((this.getPath() == null || this.getPath().length() == 0) && this.beanName != null && this.beanName.length() > 0 && this.getInterface() != null && this.getInterface().length() > 0 && this.beanName.startsWith(this.getInterface())) {
            this.setPath(this.beanName);
        }

        /**
         * 是否延迟注册服务 默认为0  以毫秒为单位
         */
        if (!this.isDelay()) {
            this.export();
        }

    }
    /**
     * 是否延迟加载
     * @return
     */
    private boolean isDelay() {
        //从当前service标签获取
        Integer delay = this.getDelay();
        ProviderConfig provider = this.getProvider();
        //如果没有设置则从provider标签获取
        if (delay == null && provider != null) {
            delay = provider.getDelay();
        }
        return this.supportedApplicationListener && (delay == null || delay == -1);
    }
    /**
     * DisposableBean实现方法
     * @throws Exception
     */
    public void destroy() throws Exception {
    }

}

真正服务发布的方法 以下方法 该方法为继承父类ServiceConfig的方法

if (!this.isDelay()) {
            this.export();
        }

ServiceConfig

L export

调用链条:ServiceBean#afterPropertiesSet#export

 public synchronized void export() {
        if (this.provider != null) {
            //<dubbo:service> 获取export配置 是否暴露服务
            if (this.export == null) {
                //从<dubbo:provider> 获取export配置  是否暴露
                this.export = this.provider.getExport();
            }
            //同上
            if (this.delay == null) {
                this.delay = this.provider.getDelay();
            }
        }
        //如果标签没有配置或者export为true 则开始暴露服务
        if (this.export == null || this.export) {
            //如果delay不等于空 或者delay大于0表示延迟加载  延迟加载使用spring 的异步事件实现
            if (this.delay != null && this.delay > 0) {
                delayExportExecutor.schedule(new Runnable() {
                    public void run() {
                        //ServiceConfig.this为内部类对象访问外部类对象的实例
                        ServiceConfig.this.doExport();
                    }
                }, (long)this.delay, TimeUnit.MILLISECONDS);
            } else {
                //直接发布
                this.doExport();
            }

        }
    }

L doExport

调用链:ServiceBean#afterPropertiesSet#export#doExport

    protected synchronized void doExport() {
        //是否下线 执行了unexport
        if (this.unexported) {
            throw new IllegalStateException("Already unexported!");
            //如果未发布
        } else if (!this.exported) {
            //设置为已发布
            this.exported = true;
            if (this.interfaceName != null && this.interfaceName.length() != 0) {
                //检查并填充provider属性
                this.checkDefault();
                if (this.provider != null) {
                    /**
                     * 如果全局有配置始终会取到 外部源码可以看出来
                     * dubbo:service没有配置application 则获取provider的Application
                     */
                    if (this.application == null) {
                        this.application = this.provider.getApplication();
                    }
                    //同上
                    if (this.module == null) {
                        this.module = this.provider.getModule();
                    }
                    //同上
                    if (this.registries == null) {
                        this.registries = this.provider.getRegistries();
                    }
                   //同上
                    if (this.monitor == null) {
                        this.monitor = this.provider.getMonitor();
                    }
                    //同上
                    if (this.protocols == null) {
                        this.protocols = this.provider.getProtocols();
                    }
                }
                //同上
                if (this.module != null) {
                    //同上
                    if (this.registries == null) {
                        this.registries = this.module.getRegistries();
                    }
                    //同上
                    if (this.monitor == null) {
                        this.monitor = this.module.getMonitor();
                    }
                }
                //同上
                if (this.application != null) {
                    //同上
                    if (this.registries == null) {
                        this.registries = this.application.getRegistries();
                    }
                    //同上
                    if (this.monitor == null) {
                        this.monitor = this.application.getMonitor();
                    }
                }
                /**
                 * 是否是泛型化暴露服务 可以查看具体文档
                 * http://dubbo.apache.org/zh-cn/docs/user/demos/generic-service.html
                 */
                if (this.ref instanceof GenericService) {
                    this.interfaceClass = GenericService.class;
                    if (StringUtils.isEmpty(this.generic)) {
                        //标识是泛型化暴露
                        this.generic = Boolean.TRUE.toString();
                    }
                } else {
                    try {
                        /**
                         * 加载指定类 第二个参数为true则被加载的时候就初始化 如果没有指定类加载器 默认使用根加载器
                         */
                        this.interfaceClass = Class.forName(this.interfaceName, true, Thread.currentThread().getContextClassLoader());
                    } catch (ClassNotFoundException var5) {
                        throw new IllegalStateException(var5.getMessage(), var5);
                    }
                    /**
                     * 检查我们配置的method标签 在接口里面是否存在 如果不存在报错
                     * <dubbo:service interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl">
                     *         <dubbo:method name="findByCategoryIds" timeout="2000"/>
                     *         <dubbo:method name="seckillTabList" timeout="2000"/>
                     *         <dubbo:method name="defaultSeckillProdcutList" timeout="2000"/>
                     *     </dubbo:service>
                     */
                    this.checkInterfaceAndMethods(this.interfaceClass, this.methods);
                    /**
                     * 检查是否配置ref标签 以及ref是否是interface实现类 如果不是抛出异常
                     */
                    this.checkRef();
                    /**
                     * 标识非泛型化暴露
                     */
                    this.generic = Boolean.FALSE.toString();
                }

                Class stubClass;
                /**
                 * dubbo local机制 已经废弃 stub代替
                 */
                if (this.local != null) {
                    if ("true".equals(this.local)) {
                        this.local = this.interfaceName + "Local";
                    }

                    try {
                        stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.local);
                    } catch (ClassNotFoundException var4) {
                        throw new IllegalStateException(var4.getMessage(), var4);
                    }

                    if (!this.interfaceClass.isAssignableFrom(stubClass)) {
                        throw new IllegalStateException("The local implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
                    }
                }
                /**
                 * 用于服务容错 服务容错实现类全名称
                 */
                if (this.stub != null) {
                    if ("true".equals(this.stub)) {
                        this.stub = this.interfaceName + "Stub";
                    }
                    try {
                        stubClass = ClassHelper.forNameWithThreadContextClassLoader(this.stub);
                    } catch (ClassNotFoundException var3) {
                        throw new IllegalStateException(var3.getMessage(), var3);
                    }
                    /**
                     * stu类必须实现服务接口
                     */
                    if (!this.interfaceClass.isAssignableFrom(stubClass)) {
                        throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + this.interfaceName);
                    }
                }

                /**
                 * 检验以下配置是否为空
                 * 并通过优先级读取填充  系统熟悉System.get properties文件
                 * dubbo.application.name
                 * dubbo.registry.address
                 */
                this.checkApplication();
                this.checkRegistry();
                this.checkProtocol();
                appendProperties(this);
                this.checkStubAndMock(this.interfaceClass);
                if (this.path == null || this.path.length() == 0) {
                    this.path = this.interfaceName;
                }
                //发布服务
                this.doExportUrls();
                ProviderModel providerModel = new ProviderModel(this.getUniqueServiceName(), this, this.ref);
                ApplicationModel.initProviderModel(this.getUniqueServiceName(), providerModel);
            } else {
                throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
            }
        }
    }

LLL doExportUrls

调用链:

调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls

    private void doExportUrls() {
        /**
         * 获得service bean的所有注册config信息 并转换为URL true表示提供者  fale表示消费者
         */
        List<URL> registryURLs = this.loadRegistries(true);
        /**
         * 获得service bean的所有协议list
         */
        Iterator i$ = this.protocols.iterator();

        //遍历协议进行服务发布
        while(i$.hasNext()) {
            ProtocolConfig protocolConfig = (ProtocolConfig)i$.next();
            this.doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }

    }

LLLL doExportUrlsFor1Protocol

调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol

 private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
        String name = protocolConfig.getName();
        if (name == null || name.length() == 0) {
            name = "dubbo";
        }

        /**
         * 存储当前服务发布相关参数信息
         * 数据例子:1
         */
        Map<String, String> map = new HashMap();
        map.put("side", "provider");
        map.put("dubbo", Version.getVersion());
        map.put("timestamp", String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put("pid", String.valueOf(ConfigUtils.getPid()));
        }

        /**
         * 将当前serviceBean相关参数设置到 map         * 逐级覆盖 methed标签优先级最高 最低是application 数据例子2
         */
        appendParameters(map, this.application);
        appendParameters(map, this.module);
        appendParameters(map, this.provider, "default");
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        /**
         * methodConfig配置不为空
         * 将methodConfig追加到参数map 如果跟全局配置一致 达到覆盖作用 如timeOut
         * 数据例子2
         */
        if (this.methods != null && !this.methods.isEmpty()) {
            Iterator i$ = this.methods.iterator();

            label188:
            while(true) {
                MethodConfig method;
                List arguments;
                do {
                    do {
                        if (!i$.hasNext()) {
                            break label188;
                        }

                        method = (MethodConfig)i$.next();
                        appendParameters(map, method, method.getName());
                        String retryKey = method.getName() + ".retry";
                        if (map.containsKey(retryKey)) {
                            String retryValue = (String)map.remove(retryKey);
                            if ("false".equals(retryValue)) {
                                map.put(method.getName() + ".retries", "0");
                            }
                        }

                        arguments = method.getArguments();
                    } while(arguments == null);
                } while(arguments.isEmpty());

                Iterator i$ = arguments.iterator();

                while(true) {
                    ArgumentConfig argument;
                    Method[] methods;
                    do {
                        do {
                            while(true) {
                                if (!i$.hasNext()) {
                                    continue label188;
                                }

                                argument = (ArgumentConfig)i$.next();
                                if (argument.getType() != null && argument.getType().length() > 0) {
                                    methods = this.interfaceClass.getMethods();
                                    break;
                                }

                                if (argument.getIndex() == -1) {
                                    throw new IllegalArgumentException("argument config must set index or type attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
                                }

                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                            }
                        } while(methods == null);
                    } while(methods.length <= 0);

                    for(int i = 0; i < methods.length; ++i) {
                        String methodName = methods[i].getName();
                        if (methodName.equals(method.getName())) {
                            Class<?>[] argtypes = methods[i].getParameterTypes();
                            if (argument.getIndex() != -1) {
                                if (!argtypes[argument.getIndex()].getName().equals(argument.getType())) {
                                    throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                }

                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                            } else {
                                for(int j = 0; j < argtypes.length; ++j) {
                                    Class<?> argclazz = argtypes[j];
                                    if (argclazz.getName().equals(argument.getType())) {
                                        appendParameters(map, argument, method.getName() + "." + j);
                                        if (argument.getIndex() != -1 && argument.getIndex() != j) {
                                            throw new IllegalArgumentException("argument config error : the index attribute and type attribute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        String contextPath;
        /**
         * 是否是泛型化发布
         */
        if (ProtocolUtils.isGeneric(this.generic)) {
            map.put("generic", this.generic);
            map.put("methods", "*");
        } else {
            contextPath = Version.getVersion(this.interfaceClass, this.version);
            if (contextPath != null && contextPath.length() > 0) {
                map.put("revision", contextPath);
            }

            String[] methods = Wrapper.getWrapper(this.interfaceClass).getMethodNames();
            if (methods.length == 0) {
                logger.warn("NO method found in service interface " + this.interfaceClass.getName());
                map.put("methods", "*");
            } else {
                map.put("methods", StringUtils.join(new HashSet(Arrays.asList(methods)), ","));
            }
        }
        /**
         * 是否开启token机制  默认为UUId
         */
        if (!ConfigUtils.isEmpty(this.token)) {
            if (ConfigUtils.isDefault(this.token)) {
                map.put("token", UUID.randomUUID().toString());
            } else {
                map.put("token", this.token);
            }
        }

        /**
         * 如果协议为本地协议( injvm ),则设置 protocolConfig#register 属性为 false ,
         * 表示不向注册中心注册服务,在 map 中存储键为 notify,值为 false,
         * 表示当注册中心监听到服务提供者发生变化(服务提供者增加、服务提供者减少等)事件时不通知。
         */
        if ("injvm".equals(protocolConfig.getName())) {
            protocolConfig.setRegister(false);
            map.put("notify", "false");
        }

        /**
         * 设置协议的 contextPath,如果未配置,默认为 /interfacename
         */
        contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && this.provider != null) {
            contextPath = this.provider.getContextpath();
        }

        /**
         * 解析服务提供者的IP地址与端口。并追加到map
         */
        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        Integer port = this.findConfigedPorts(protocolConfig, name, map);
        /**
         * 根据map和上下文组织Url
         * 数据例子:3
         */
        URL url = new URL(name, host, port, (contextPath != null && contextPath.length() != 0 ? contextPath + "/" : "") + this.path, map);
        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).hasExtension(url.getProtocol())) {
            url = ((ConfiguratorFactory)ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getExtension(url.getProtocol())).getConfigurator(url).configure(url);
        }

        /**
         * 构建invoker实例
         * 获取dubbo:service配置的scope属性
         * 其可选值为 none (不暴露)、local (本地)、remote (远程),如果配置为 none,则不暴露。默认为 local。
         */
        String scope = url.getParameter("scope");
        if (!"none".toString().equalsIgnoreCase(scope)) {
            /**
             * 则先在本地暴露( injvm )
             */
            if (!"remote".toString().equalsIgnoreCase(scope)) {
                this.exportLocal(url);
            }
            /**
             * 如果 scope 不为 local,则将服务暴露在远程。
             */
            if (!"local".toString().equalsIgnoreCase(scope)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Export dubbo service " + this.interfaceClass.getName() + " to url " + url);
                }

                /**
                 * 如果注册中心不为空 则遍历注册中心 依次注册到注册中心
                 */
                if (registryURLs != null && !registryURLs.isEmpty()) {
                    Iterator i$ = registryURLs.iterator();

                    while(i$.hasNext()) {
                        URL registryURL = (URL)i$.next();
                        /**
                         * 如果 dubbo:service 的 dynamic 属性未配置,
                         * 尝试取 dubbo:registry 的 dynamic 属性,该属性的作用是否启用动态注册,如果设置为 false,服务注册后,
                         * 其状态显示为 disable,需要人工启用,当服务不可用时,也不会自动移除,同样需要人工处理,此属性不要在生产环境上配置
                         */
                        url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        URL monitorUrl = this.loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded("monitor", monitorUrl.toFullString());
                        }

                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + this.interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
                        /**
                         * 构建Invoker实例 dubbo远程调用实例
                         * spi
                         *private static final ProxyFactory proxyFactory = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
                         *这里取得的是com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
                         * 数据例子4
                         */
                        Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, registryURL.addParameterAndEncoded("export", url.toFullString()));
                        //DelegateProviderMetaDataInvoker对象增加一层代理 内部保存源对象以及invoker 代理对象 执行器
                        DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                        /**
                         * 根据指定协议本地暴露和向注册中心注册服务
                         * SPI 这里取的是com.alibaba.dubbo.rpc.protocol.dubbo.ProtocolFilterWrapper和ProtocolListennerWrapper包装拦截器以及触发监听器 具体参考签名SPI
                         * 数据例子5
                         * private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
                         */
                        Exporter<?> exporter = protocol.export(wrapperInvoker);
                        this.exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(this.ref, this.interfaceClass, url);
                    DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this);
                    Exporter<?> exporter = protocol.export(wrapperInvoker);
                    this.exporters.add(exporter);
                }
            }
        }

        this.urls.add(url);
    }

数据例子1

数据例子2

  <dubbo:service timeout="500" interface="com.biz.soa.service.seckill.frontend.SoaSeckillFrontService" ref="soaSeckillFrontServiceImpl"><dubbo:method name="findByCategoryIds" timeout="2000"/><dubbo:method name="seckillTabList" timeout="2000"/><dubbo:method name="defaultSeckillProdcutList" timeout="2000"/></dubbo:service

数据例子3

数据例子4

@SPI("javassist")
public interface ProxyFactory {
    @Adaptive({"proxy"})
    <T> T getProxy(Invoker<T> var1) throws RpcException;

    @Adaptive({"proxy"})
    <T> Invoker<T> getInvoker(T var1, Class<T> var2, URL var3) throws RpcException;
}

数据例子5

@SPI("dubbo")
public interface Protocol {
    int getDefaultPort();

    @Adaptive
    <T> Exporter<T> export(Invoker<T> var1) throws RpcException;

    @Adaptive
    <T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;

    void destroy();
}

LLLLL findConfigedHosts

调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol#findConfigedHosts

/**
     * 获得暴露ip
     * @param protocolConfig
     * @param registryURLs
     * @param map
     * @return
     */
    private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
        boolean anyhost = false;
        /**
         * 从系统变量->环境变量获取DUBBO_DUBBO_IP_TO_BIND的值    第一个DUBBO取得protocolConfig配置的name
         */
        String hostToBind = this.getValueFromConfig(protocolConfig, "DUBBO_IP_TO_BIND");
        //如果取到则校验有效性
        if (hostToBind != null && hostToBind.length() > 0 && NetUtils.isInvalidLocalHost(hostToBind)) {
            throw new IllegalArgumentException("Specified invalid bind ip from property:DUBBO_IP_TO_BIND, value:" + hostToBind);
        } else {
            if (hostToBind == null || hostToBind.length() == 0) {
                //取protocol配置的host
                hostToBind = protocolConfig.getHost();
                //如果protocol没有渠道则取provider配置的ip
                if (this.provider != null && (hostToBind == null || hostToBind.length() == 0)) {
                    hostToBind = this.provider.getHost();
                }
                //如果也没有取到
                if (NetUtils.isInvalidLocalHost(hostToBind)) {
                    anyhost = true;

                    try {
                        //遍历网卡获取ip地址
                        hostToBind = InetAddress.getLocalHost().getHostAddress();
                    } catch (UnknownHostException var20) {
                        logger.warn(var20.getMessage(), var20);
                    }
                     //如果还不符合继续匹配 取依次取有效 注册中心地址
                    if (NetUtils.isInvalidLocalHost(hostToBind)) {
                        if (registryURLs != null && !registryURLs.isEmpty()) {
                            Iterator i$ = registryURLs.iterator();

                            label189:
                            while(true) {
                                URL registryURL;
                                do {
                                    if (!i$.hasNext()) {
                                        break label189;
                                    }

                                    registryURL = (URL)i$.next();
                                } while("multicast".equalsIgnoreCase(registryURL.getParameter("registry")));

                                try {
                                    Socket socket = new Socket();

                                    try {
                                        SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
                                        socket.connect(addr, 1000);
                                        //建立连接成功表示有效 取这个注册中心地址
                                        hostToBind = socket.getLocalAddress().getHostAddress();
                                        break;
                                    } finally {
                                        try {
                                            //释放连接
                                            socket.close();
                                        } catch (Throwable var18) {
                                            ;
                                        }

                                    }
                                } catch (Exception var21) {
                                    logger.warn(var21.getMessage(), var21);
                                }
                            }
                        }

                        if (NetUtils.isInvalidLocalHost(hostToBind)) {
                            hostToBind = NetUtils.getLocalHost();
                        }
                    }
                }
            }
            //将取到的bind ip追加到参数列表
            map.put("bind.ip", hostToBind);
            //从系统变量->环境变量获取DUBBO_DUBBO_IP_TO_REGISTRY 下面可以看到这个优先级最大如果没有渠道 则使用hostToBind
            String hostToRegistry = this.getValueFromConfig(protocolConfig, "DUBBO_IP_TO_REGISTRY");
            if (hostToRegistry != null && hostToRegistry.length() > 0 && NetUtils.isInvalidLocalHost(hostToRegistry)) {
                throw new IllegalArgumentException("Specified invalid registry ip from property:DUBBO_IP_TO_REGISTRY, value:" + hostToRegistry);
            } else {
                if (hostToRegistry == null || hostToRegistry.length() == 0) {
                    hostToRegistry = hostToBind;
                }
                //是否取到host
                map.put("anyhost", String.valueOf(anyhost));
                return hostToRegistry;
            }
        }
    }

LLLLL findConfigedPorts

调用链:ServiceBean#afterPropertiesSet#export#doExport#doExportUrls#doExportUrlsFor1Protocol#findConfigedPorts

/**
     * 获得暴露的端口
     * @param protocolConfig
     * @param name
     * @param map
     * @return
     */
    private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
        Integer portToBind = null;
        /**
         * 在系统变量|环境变量获得#{protocol.name.toUpperCase}_DUBBO_PORT_TO_BIND 绑定端口
         */
        String port = this.getValueFromConfig(protocolConfig, "DUBBO_PORT_TO_BIND");
        //如果配置的是有效的 string转为Integer
        portToBind = this.parsePort(port);
        //如果没取到
        if (portToBind == null) {
            //取protocol配置的Port
            portToBind = protocolConfig.getPort();
            //如果没取到则取provider配置
            if (this.provider != null && (portToBind == null || portToBind == 0)) {
                portToBind = this.provider.getPort();
            }
            //根据配置的协议 通过SPI获取对应的协议实现并获得默认port 这里name是dubbo
            //数据例子:1
            int defaultPort = ((Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(name)).getDefaultPort();
            //如果没获取到port则使用默认的
            if (portToBind == null || portToBind == 0) {
                portToBind = defaultPort;
            }
            //如果还是没取到 随机获取
            if (portToBind == null || portToBind <= 0) {
                portToBind = getRandomPort(name);
                if (portToBind == null || portToBind < 0) {
                    portToBind = NetUtils.getAvailablePort(defaultPort);
                    putRandomPort(name, portToBind);
                }

                logger.warn("Use random available port(" + portToBind + ") for protocol " + name);
            }
        }

        map.put("bind.port", String.valueOf(portToBind));
        /**
         * 获取系统变量|环境变量 #{protocol.name.toUpperCase}_DUBBO_PORT_TO_REGISTRY配置的port
         * 此优先级最大
         */
        String portToRegistryStr = this.getValueFromConfig(protocolConfig, "DUBBO_PORT_TO_REGISTRY");
        //如果正常类型则转为Integer返回
        Integer portToRegistry = this.parsePort(portToRegistryStr);
        if (portToRegistry == null) {
            portToRegistry = portToBind;
        }

        return portToRegistry;
    }

数据例子1

JavassistProxyFactory

LLLLLL getInvoker

/**
 * 代理实现
 */
public class JavassistProxyFactory extends AbstractProxyFactory {
    public JavassistProxyFactory() {
    }

    /**
     * jdk动态代理
     * @param invoker
     * @param interfaces
     * @param <T>
     * @return
     */
    public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
        return Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    }

    /**
     * 采用javassis 动态生成类以及创建对象的生成代理 直接调用的方式 而不是使用jdk代理 反射调用方式 因为性能原因
     * @param proxy
     * @param type
     * @param url
     * @param <T>
     * @return
     */
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf(36) < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

RegistryProtocol

export

调用链:ServiceBean.afterPropertiesSet#ServiceConfig.export#ServiceConfig.doExport#ServiceConfig.doExportUrlsFor1Protocol#RegistryProtocol.export

 public <T> Exporter<T> export(Invoker<T> originInvoker) throws RpcException {
        /**
         * 本地暴露服务
         */
        RegistryProtocol.ExporterChangeableWrapper<T> exporter = this.doLocalExport(originInvoker);
        /**
         * 获取注册中心地址
         * 数据例子1
         */
        URL registryUrl = this.getRegistryUrl(originInvoker);
        /**
         * 获得注册中心实现类 这里为ZookeeperRegistry
         * 数据例子2
         */
        Registry registry = this.getRegistry(originInvoker);
        /**
         * 获取注册的服务地址
         * 数据例子3
         */
        URL registedProviderUrl = this.getRegistedProviderUrl(originInvoker);
        boolean register = registedProviderUrl.getParameter("register", true);
        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);
        if (register) {
            this.register(registryUrl, registedProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

        URL overrideSubscribeUrl = this.getSubscribedOverrideUrl(registedProviderUrl);
        RegistryProtocol.OverrideListener overrideSubscribeListener = new RegistryProtocol.OverrideListener(overrideSubscribeUrl, originInvoker);
        this.overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        //像注册中心发布自己
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        return new RegistryProtocol.DestroyableExporter(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
    }

数据例子1

数据例子2

数据例子3

doLocalExport

private <T> RegistryProtocol.ExporterChangeableWrapper<T> doLocalExport(Invoker<T> originInvoker) {
        String key = this.getCacheKey(originInvoker);
        RegistryProtocol.ExporterChangeableWrapper<T> exporter = (RegistryProtocol.ExporterChangeableWrapper)this.bounds.get(key);
        if (exporter == null) {
            Map var4 = this.bounds;
            synchronized(this.bounds) {
                exporter = (RegistryProtocol.ExporterChangeableWrapper)this.bounds.get(key);
                if (exporter == null) {
                    Invoker<?> invokerDelegete = new RegistryProtocol.InvokerDelegete(originInvoker, this.getProviderUrl(originInvoker));
                    //这里会调用DubboProtocol 暴露自己 this.protocol.export(invokerDelegete)
                    exporter = new RegistryProtocol.ExporterChangeableWrapper(this.protocol.export(invokerDelegete), originInvoker);
                    this.bounds.put(key, exporter);
                }
            }
        }

        return exporter;
    }

dubbo-源码阅读之服务发布的更多相关文章

  1. dubbo 源码学习1 服务发布机制

    1.源码版本:2.6.1 源码demo中采用的是xml式的发布方式,在dubbo的 DubboNamespaceHandler 中定义了Spring Framework 的扩展标签,即 <dub ...

  2. dubbo源码阅读之服务导出

    dubbo服务导出 常见的使用dubbo的方式就是通过spring配置文件进行配置.例如下面这样 <?xml version="1.0" encoding="UTF ...

  3. dubbo源码阅读之服务目录

    服务目录 服务目录对应的接口是Directory,这个接口里主要的方法是 List<Invoker<T>> list(Invocation invocation) throws ...

  4. dubbo源码阅读之服务引入

    服务引入 服务引入使用reference标签来对要引入的服务进行配置,包括服务的接口 ,名称,init,check等等配置属性. 在DubboNamespaceHandler中,我们可以看到refer ...

  5. 【Dubbo源码阅读系列】服务暴露之远程暴露

    引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...

  6. 【Dubbo源码阅读系列】服务暴露之本地暴露

    在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...

  7. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  8. Dubbo源码学习之-服务导出

    前言 忙的时候,会埋怨学习的时间太少,缺少个人的空间,于是会争分夺秒的工作.学习.而一旦繁忙的时候过去,有时间了之后,整个人又会不自觉的陷入一种懒散的状态中,时间也显得不那么重要了,随便就可以浪费掉几 ...

  9. 【Dubbo源码阅读系列】之 Dubbo SPI 机制

    最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...

  10. Dubbo源码阅读顺序

    转载: https://blog.csdn.net/heroqiang/article/details/85340958 Dubbo源码解析之配置解析篇,主要内容是<dubbo:service/ ...

随机推荐

  1. HTML中的img标签属性

    <img>标签 标签用于插入图片.它是单独使用的,没有闭合标签. <img src="https://fakeimg.pl/350x200/ff0000,128/000,2 ...

  2. Base64和3DES算法

    Base64加密算法 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息.它的优点是算法效率高,编码出来的结果比较简短,同时也具有不可读性. ...

  3. 【dart学习】-- Dart之异步编程

    一,概述 编程中的代码执行,通常分为同步与异步两种. 同步:简单说,同步就是按照代码的编写顺序,从上到下依次执行,这也是最简单的我们最常接触的一种形式.但是同步代码的缺点也显而易见,如果其中某一行或几 ...

  4. SCP-Py-002

    项目编号:Py-002 项目等级:EuclidKeter 特殊收容措施: Py-002-1目前被映射在Researcher Kevin的服务器位于Site-Pyproject地下防无线电渗透室且被切断 ...

  5. BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡(高斯消元+期望dp)

    传送门 解题思路 设\(f(x)\)表示到\(x\)这个点的期望次数,那么转移方程为\(f(x)=\sum\frac{f(u)*(1 - \frac{p}{q})}{deg(u)}\),其中\(u\) ...

  6. LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT

    题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...

  7. ip协议,IP,子网掩码,ping命令是什么

    ip协议: 定网络地址的协议叫ip协议,它定义的地址称之为ip地址,广泛采用的v4版本即ipv4,它规定网络地址由32位2进制表示 IP地址:是给每个连接在Internet上的主机分配的一个32bit ...

  8. (2)C++基本类型

    一.整形 short .int. long. long long sizeof查看类型所占的字节数 cout << sizeof(short)<<endl;//2 字节 cou ...

  9. SPSS输出的结果都要写到文章中吗

    SPSS输出的结果都要写到文章中吗 经常有人问到,SPSS输出的结果都要写到文章中吗?文章中应该写什么呢?比如,均值.中位数.众数.标准差.百分位数.最小值.最大值等等,都要出现在文章中吗?洋洋洒洒那 ...

  10. day 62.3 Django基础八之cookie和session

    Django基础八之cookie和session   本节目录 一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session 六 xxx ...