天天看點

Dubbo源碼學習筆記(提供方服務暴露serviceBean)

 前面一篇文章主要是對dubbo的xml中所配置的内容進行解析以及參數的綁定,進而實作整個bean的注冊,文章的結尾也有提到,dubbo的服務暴露以及服務訂閱是通過子類進行擴充并協同父類實作相應的功能,下面主要來解讀一下serviceBean服務的暴露,直接源碼如下:

/*最主要的兩個bean,一個服務提供方的暴露服務ServiceBean以及一個服務消費方的訂閱服務ReferenceBean。
首先來看serviceBean的源碼:*/
	
	
	public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {

    private static final long serialVersionUID = 213195494150089726L;

    private static transient ApplicationContext SPRING_CONTEXT;

    private final transient Service service;

    private transient ApplicationContext applicationContext;

    private transient String beanName;

    private transient boolean supportedApplicationListener;

    public ServiceBean() {
        super(); /*ServiceConfig必須先進行,這裡與另外的幾個Config是沒有什麼差別的。*/
        this.service = null;
    }

    public ServiceBean(Service service) {
        super(service);
        this.service = service;
    }

    public static ApplicationContext getSpringContext() {
        return SPRING_CONTEXT;
    }

	/*實作了ApplicationContextAware,重寫了setApplicationContext,以便将spring中的applicationContext拿到dubbo中來使用,并儲存到SpringExtensionFactory*/
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        SpringExtensionFactory.addApplicationContext(applicationContext);
        if (applicationContext != null) {
            SPRING_CONTEXT = applicationContext;
            try {
                Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); 
                method.invoke(applicationContext, new Object[]{this});
                supportedApplicationListener = true;
            } catch (Throwable t) {
                if (applicationContext instanceof AbstractApplicationContext) {
                    try {
                        Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); 
                        if (!method.isAccessible()) {
                            method.setAccessible(true);
                        }
                        method.invoke(applicationContext, new Object[]{this});
                        supportedApplicationListener = true;
                    } catch (Throwable t2) {
                    }
                }
            }
        }
    }
	/*實作了BeanNameAware接口,重寫了此方法*/
    public void setBeanName(String name) {
        this.beanName = name;
    }

    /**
     * Gets associated {@link Service}
     *
     * @return associated {@link Service}
     */
    public Service getService() {
        return service;
    }
	/*服務監聽,沒有設定延遲或者延遲為-1,dubbo會在Spring執行個體化完bean之後,在重新整理容器最後一步釋出ContextRefreshEvent事件的時候,
	通知實作了ApplicationListener的類進行回調onApplicationEvent,dubbo會在這個方法中釋出服務。*/
    public void onApplicationEvent(ApplicationEvent event) {
        if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
            if (isDelay() && !isExported() && !isUnexported()) {
                if (logger.isInfoEnabled()) {
                    logger.info("The service ready on spring started. service: " + getInterface());
                }
                export();
            }
        }
    }

    private boolean isDelay() {
        Integer delay = getDelay();
        ProviderConfig provider = getProvider();
        if (delay == null && provider != null) {
            delay = provider.getDelay();
        }
        return supportedApplicationListener && (delay == null || delay == -1);
    }

    @SuppressWarnings({"unchecked", "deprecation"})
	/*dubbo在Spring執行個體化bean(initializeBean)的時候會對實作了InitializingBean的類進行回調,回調方法就是此方法*/
    public void afterPropertiesSet() throws Exception {
		/*此serviceBean提供者為空*/
        if (getProvider() == null) {
			/*applicationContext不為空的情況下則從applicationContext中擷取提供者bean集合,比如:在提供方配置的<dubbo:provider>*/
            Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
            if (providerConfigMap != null && providerConfigMap.size() > 0) {
				/*applicationContext不為空的情況下則從applicationContext中擷取協定bean集合,比如:在提供方配置的<dubbo:protocol>*/
                Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false);
                /*沒有擷取到協定配置 && 提供者集合中有元素*/
				if ((protocolConfigMap == null || protocolConfigMap.size() == 0)
                        && providerConfigMap.size() > 1) {    /*相容舊版本*/
                    List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
					/*周遊提供者bean集合*/
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() != null && config.isDefault().booleanValue()) {
                            providerConfigs.add(config);
                        }
                    }
					/*為此serviceBean添加提供者清單,設定到對應的屬性*/
                    if (providerConfigs.size() > 0) {
                        setProviders(providerConfigs);
                    }
				/*反之,直接周遊提供者集合*/
                } else {
                    ProviderConfig providerConfig = null;
					/*周遊提供者bean集合*/
                    for (ProviderConfig config : providerConfigMap.values()) {
                        if (config.isDefault() == null || config.isDefault().booleanValue()) {
							/*如果在這個providerConfigMap周遊出一樣配置,将抛出異常,提示重複的提供者配置*/
                            if (providerConfig != null) {
                                throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
					/*為此serviceBean設定提供者,設定到對應的屬性*/
                    if (providerConfig != null) {
                        setProvider(providerConfig);
                    }
                }
            }
        }
		/*此serviceBean應用配置資訊為空 && (提供者為空 || 提供者中也沒有配置應用資訊)*/
        if (getApplication() == null
                && (getProvider() == null || getProvider().getApplication() == null)) {
				/*applicationContext不為空的情況下則從applicationContext中擷取應用配置bean集合,比如:在提供方配置的<dubbo:application name="">則
				 * 這裡拿到的就是這樣{dubbo_zht_core=<dubbo:application name="dubbo_zht_core" id="dubbo_zht_core" />}*/
				 */
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? 
            		null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false);
            if (applicationConfigMap != null && applicationConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
				/*周遊應用配置資訊bean集合*/
                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;
                    }
                }
				/*為此serviceBean設定應用資訊,設定到對應的屬性*/
                if (applicationConfig != null) {
                    setApplication(applicationConfig);
                }
            }
        }
		/*此serviceBean子產品配置資訊為空 && (提供者為空 || 提供者中也沒有配置子產品資訊)*/
        if (getModule() == null
                && (getProvider() == null || getProvider().getModule() == null)) {
				/*applicationContext不為空的情況下則從applicationContext中擷取子產品配置資訊bean集合,比如:在提供方配置的 <dubbo:module> */
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false);
            if (moduleConfigMap != null && moduleConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                /*周遊子產品配置資訊bean集合*/
				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;
                    }
                }
				/*為此serviceBean設定子產品配置資訊,設定到對應的屬性*/
                if (moduleConfig != null) {
                    setModule(moduleConfig);
                }
            }
        }
		/*此serviceBean注冊中心配置資訊為空 && (提供者為空 || 提供者中也沒有配置注冊中心資訊) && (應用配置資訊為空 || 應用配置資訊中也沒有配置注冊中心)*/
        if ((getRegistries() == null || getRegistries().size() == 0)
                && (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().size() == 0)
                && (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
				/*applicationContext不為空的情況下則從applicationContext中擷取注冊中心配置資訊bean集合,比如:在提供方配置的 <dubbo:registry>*/
            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>();
				/*周遊注冊中心配置bean集合*/
                for (RegistryConfig config : registryConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        registryConfigs.add(config);
                    }
                }
				/*為此serviceBean的父類設定注冊中心配置資訊,設定到對應的屬性*/
                if (registryConfigs != null && registryConfigs.size() > 0) {
                    super.setRegistries(registryConfigs);
                }
            }
        }
		/*此serviceBean監控中心為空 && (提供者為空 || 提供者中也沒有監控中心資訊) && (應用配置資訊為空 || 應用配置資訊中也沒有配置監控中心))*/
        if (getMonitor() == null
                && (getProvider() == null || getProvider().getMonitor() == null)
                && (getApplication() == null || getApplication().getMonitor() == null)) {
				/*applicationContext不為空的情況下則從applicationContext中擷取監控中心配置資訊bean集合,比如:在提供方配置的 <dubbo:monitor>*/
            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;
                    }
                }
				/*為此serviceBean設定監控中心配置資訊,設定到對應的屬性*/
                if (monitorConfig != null) {
                    setMonitor(monitorConfig);
                }
            }
        }
		/*此serviceBean協定配置為空 && (提供者為空 || 提供者中也沒有配置協定資訊)*/
        if ((getProtocols() == null || getProtocols().size() == 0)
                && (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().size() == 0)) {
				/*applicationContext不為空的情況下則從applicationContext中擷取協定配置資訊bean集合,比如:在提供方配置的 <dubbo:protocol>*/
            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>();
				/*周遊協定資訊bean集合,取出協定裝入清單中*/
                for (ProtocolConfig config : protocolConfigMap.values()) {
                    if (config.isDefault() == null || config.isDefault().booleanValue()) {
                        protocolConfigs.add(config);
                    }
                }
				/*為此serviceBean設定協定配置資訊清單,設定到對應的屬性*/
                if (protocolConfigs != null && protocolConfigs.size() > 0) {
                    super.setProtocols(protocolConfigs);
                }
            }
        }
		/*此serviceBean服務路徑配置為空 */
        if (getPath() == null || getPath().length() == 0) {
			/*bean的名稱不為空 && 服務接口名不為空 && bean的名稱是與服務接口名稱開頭,這個beanName就是xml中<dubbo:service inter/>*/
            if (beanName != null && beanName.length() > 0
                    && getInterface() != null && getInterface().length() > 0
                    && beanName.startsWith(getInterface())) {
				/*會使用正規表達式對beanName進行校驗是否合法*/
                setPath(beanName);
            }
        }
		/*如果設定了延遲暴露,dubbo在這個export方法裡面會另外建立一個線程進行服務的釋出*/
        if (!isDelay()) {
            export();/*這裡就是真正服務進行暴露的入口,調用父類的方法*/
        }
    }
	/*實作了DisposableBean,在bean銷毀前做哪些操作?則調用unexport*/
    public void destroy() throws Exception {
        unexport();
    }

}

/*下面為調用父類ServiceConfig中export方法以及關聯方法源碼:*/
  public synchronized void export() {
        if (provider != null) {
            if (export == null) {
                export = provider.getExport();
            }
            if (delay == null) {
                delay = provider.getDelay();
            }
        }
        if (export != null && !export) {
            return;
        }
			/*如果設定了延遲暴露,那麼這裡會建立一個線程進行延遲處理*/
        if (delay != null && delay > 0) {
            delayExportExecutor.schedule(new Runnable() {
                public void run() {
                    doExport();
                }
            }, delay, TimeUnit.MILLISECONDS);
        } else {
            doExport();
        }
    }

    protected synchronized void doExport() {
        if (unexported) {
            throw new IllegalStateException("Already unexported!");
        }
        if (exported) {
            return;
        }
        exported = true;
		/*暴露接口名稱不能為空*/
        if (interfaceName == null || interfaceName.length() == 0) {
            throw new IllegalStateException("<dubbo:service inter\" /> interface not allow null!");
        }
		/*校驗服務提供方是否配有預設的提供者,即使在服務提供方配了一個無法找到的IP以及端口的provider在這裡也不會報錯*/
        checkDefault();
        if (provider != null) {
            if (application == null) {
                application = provider.getApplication();
            }
            if (module == null) {
                module = provider.getModule();
            }
            if (registries == null) {
                registries = provider.getRegistries();
            }
            if (monitor == null) {
                monitor = provider.getMonitor();
            }
            if (protocols == null) {
                protocols = provider.getProtocols();
            }
        }
        if (module != null) {
            if (registries == null) {
                registries = module.getRegistries();
            }
            if (monitor == null) {
                monitor = module.getMonitor();
            }
        }
        if (application != null) {
            if (registries == null) {
                registries = application.getRegistries();
            }
            if (monitor == null) {
                monitor = application.getMonitor();
            }
        }
        if (ref instanceof GenericService) {
            interfaceClass = GenericService.class;
            if (StringUtils.isEmpty(generic)) {
                generic = Boolean.TRUE.toString();
            }
        } else {
            try {
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
			/*如果配置了<dubbo:method>則會校驗此interfaceClass中的方法與你配置的是否一緻,如果你配的這個方法在此interfaceClass中根本找不到則會抛出IllegalStateException異常,*/
			/*當然,如果你配了個<dubbo:method>空标簽那麼早就在DubboBeanDefinitionParser中抛出異常了,還走不到這裡*/
            checkInterfaceAndMethods(interfaceClass, methods);
			/*校驗<dubbo:service>中interface的執行個體是不是ref指向的這個執行個體,如果ref為空或者這兩個不比對,也就是沒有實作接口則會抛出IllegalStateException異常*/
            checkRef();
            generic = Boolean.FALSE.toString();
        }
		/*如果是本地服務,則再服務名稱後面加上Local*/
        if (local != null) {
            if ("true".equals(local)) {
                local = interfaceName + "Local";
            }
            Class<?> localClass;
            try {
                localClass = ClassHelper.forNameWithThreadContextClassLoader(local);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(localClass)) {
                throw new IllegalStateException("The local implementation class " + localClass.getName() + " not implement interface " + interfaceName);
            }
        }
		/*如果是遠端服務,則再服務名稱後面加上Stub*/
        if (stub != null) {
            if ("true".equals(stub)) {
                stub = interfaceName + "Stub";
            }
            Class<?> stubClass;
            try {
                stubClass = ClassHelper.forNameWithThreadContextClassLoader(stub);
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            if (!interfaceClass.isAssignableFrom(stubClass)) {
                throw new IllegalStateException("The stub implementation class " + stubClass.getName() + " not implement interface " + interfaceName);
            }
        }
		/*校驗服務方應用配置資訊是否為空,如果為空則根據key到系統屬性中擷取,如果還是沒有擷取到則會抛出異常,如果擷取到了則會新建立一個ApplicationConfig,并将系統中擷取的對應的屬性值指派給ApplicationConfig。*/
        checkApplication();
		/*校驗注冊中心配置資訊是否為空,如果為空則根據key到系統屬性中擷取,如果還是沒有擷取到則會抛出異常,如果擷取到了則會新建立一個RegistryConfig,并将系統中擷取的對應的屬性值指派給RegistryConfig,有多個則循環多次操作。*/
        checkRegistry();
		/*校驗協定配置資訊是否為空,如果為空則試圖從<dubbo:provider>中擷取,如果provider也是null,則預設使用dubbo協定*/
        checkProtocol();
		/*将目前對象執行個體傳入此方法進行屬性完整化,如serviceBean*/
        appendProperties(this);
		/*檢查遠端和本地服務接口真實存在(是否可load)以及是否可以服務降級*/
        checkStubAndMock(interfaceClass);
        if (path == null || path.length() == 0) {
            path = interfaceName;
        }
		 /*暴露位址*/
        doExportUrls();
    }


    public synchronized void unexport() {
        if (!exported) {
            return;
        }
        if (unexported) {
            return;
        }
        if (exporters != null && exporters.size() > 0) {
            for (Exporter<?> exporter : exporters) {
                try {
                    exporter.unexport();
                } catch (Throwable t) {
                    logger.warn("unexpected err when unexport" + exporter, t);
                }
            }
            exporters.clear();
        }
        unexported = true;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void doExportUrls() {
		/*将所有需要的資訊進行組裝,成為注冊中心的URL(ip、注冊接口、pid、時間戳)*/
        List<URL> registryURLs = loadRegistries(true);
        for (ProtocolConfig protocolConfig : protocols) {
            doExportUrlsFor1Protocol(protocolConfig, registryURLs);
        }
    }

    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>();
        map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE);
        map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion());
        map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
        if (ConfigUtils.getPid() > 0) {
            map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid()));
        }
		/*将必要的資訊都添加進map中*/
        appendParameters(map, application);
        appendParameters(map, module);
        appendParameters(map, provider, Constants.DEFAULT_KEY);
        appendParameters(map, protocolConfig);
        appendParameters(map, this);
        if (methods != null && methods.size() > 0) {
            for (MethodConfig method : methods) {
                appendParameters(map, method, method.getName());
                String retryKey = method.getName() + ".retry";
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        map.put(method.getName() + ".retries", "0");
                    }
                }
                List<ArgumentConfig> arguments = method.getArguments();
                if (arguments != null && arguments.size() > 0) {
                    for (ArgumentConfig argument : arguments) {
                        /*類型自動轉換.  */
                        if (argument.getType() != null && argument.getType().length() > 0) {
                            Method[] methods = interfaceClass.getMethods();
                            /*周遊所有方法 */
                            if (methods != null && 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();
                                        /*一個方法中單個callback  */
                                        if (argument.getIndex() != -1) {
                                            if (argtypes[argument.getIndex()].getName().equals(argument.getType())) {
                                                appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                                            } else {
                                                throw new IllegalArgumentException("argument config error : the 
index attribute and type attirbute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                            }
                                        } else {
                                            /*一個方法中多個callback  */
                                            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 attirbute not match :index :" + argument.getIndex() + ", type:" + argument.getType());
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        } else if (argument.getIndex() != -1) {
                            appendParameters(map, argument, method.getName() + "." + argument.getIndex());
                        } else {
                            throw new IllegalArgumentException("argument config must set index or type 
attribute.eg: <dubbo:argument index='0' .../> or <dubbo:argument type=xxx .../>");
                        }

                    }
                }
            } /* end of methods for*/
        }

        if (ProtocolUtils.isGeneric(generic)) {
            map.put("generic", generic);
            map.put("methods", Constants.ANY_VALUE);
        } else {
            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("methods", Constants.ANY_VALUE);
            } else {
                map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ","));
            }
        }
        if (!ConfigUtils.isEmpty(token)) {
            if (ConfigUtils.isDefault(token)) {
                map.put("token", UUID.randomUUID().toString());
            } else {
                map.put("token", token);
            }
        }
        if ("injvm".equals(protocolConfig.getName())) {
            protocolConfig.setRegister(false);
            map.put("notify", "false");
        }
        /*  導出服務 */
        String contextPath = protocolConfig.getContextpath();
        if ((contextPath == null || contextPath.length() == 0) && provider != null) {
            contextPath = provider.getContextpath();
        }
		/*provider注冊&監聽ip位址,注冊與監聽ip可獨立配置 配置優先級:系統環境變量 -> java指令參數-D -> 
		 * 配置檔案host屬性 -> /etc/hosts中hostname-ip映射關系 -> 預設聯通注冊中心位址的網卡位址 -> 第一個可用的網卡位址*/
        String host = this.findConfigedHosts(protocolConfig, registryURLs, map);
        /*provider注冊&監聽端口,注冊與監聽port可獨立配置 配置優先級:啟動環境變量 -> java指令參數-D -> protocol配置檔案port屬性配置 -> 協定預設端口*/
		Integer port = this.findConfigedPorts(protocolConfig, name, map);
		/*建立服務所在url  */
        URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map);

        if (ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                .hasExtension(url.getProtocol())) {
            url = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
                    .getExtension(url.getProtocol()).getConfigurator(url).configure(url);
        }
		/*擷取服務暴露作用域*/
        String scope = url.getParameter(Constants.SCOPE_KEY);
           /*配置為none不暴露,如果什麼都沒配的話即暴露本地又暴露遠端*/
        if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) {

            /*配置不是remote的情況下做本地暴露 (配置為remote,則表示隻暴露遠端服務)*/
            if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
                exportLocal(url);
            }
            /*如果配置不是local則暴露為遠端服務.(配置為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.size() > 0
                        && url.getParameter("register", true)) {
                    for (URL registryURL : registryURLs) {
                        url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
                        URL monitorUrl = loadMonitor(registryURL);
                        if (monitorUrl != null) {
                            url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
                        }
                        if (logger.isInfoEnabled()) {
                            logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
                        }
						/*通過proxyFactory擷取一個AbstractProxyInvoker執行個體Invoker,這個proxyFactory是JavassistProxyFactory、JdkProxyFactory中的一個,我在調試時看到的是JavassistProxyFactory*/
                        Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
						/*protocol根據實際調用時的不同而使用的協定則不同,我在調試時看到的是RegistryProtocol,在調RegistryProtocol的export前會先調用ProtocollistenerWrapper的export方法對protocol執行個體wrapper*/
                        Exporter<?> exporter = protocol.export(invoker);
                        exporters.add(exporter);
                    }
                } else {
                    Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);

                    Exporter<?> exporter = protocol.export(invoker);
                    exporters.add(exporter);
                }
            }
        }
        this.urls.add(url);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void exportLocal(URL url) {
        if (!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) {
            URL local = URL.valueOf(url.toFullString())
                    .setProtocol(Constants.LOCAL_PROTOCOL)
                    .setHost(LOCALHOST)
                    .setPort(0);
            Exporter<?> exporter = protocol.export(
                    proxyFactory.getInvoker(ref, (Class) interfaceClass, local));
            exporters.add(exporter);
            logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry");
        }
    }


     /**
     * provider注冊&監聽ip位址,注冊與監聽ip可獨立配置
     * 配置優先級:系統環境變量 -> java指令參數-D -> 配置檔案host屬性 -> /etc/hosts中hostname-ip映射關系 -> 預設聯通注冊中心位址的網卡位址 -> 第一個可用的網卡位址
     *
     * @param protocolConfig
     * @param registryURLs
     * @param map
     * @return
     */
    private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
        boolean anyhost = false;
		/*從系統環境變量中擷取IP*/
        String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND);
        if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
            throw new IllegalArgumentException("Specified invalid bind ip from property:" + Constants.DUBBO_IP_TO_BIND + ", value:" + hostToBind);
        }

        /* 如果沒通過系統環境變量設定bind ip,則繼續按優先級查找*/
        if (hostToBind == null || hostToBind.length() == 0) {
			/*從配置檔案中擷取host*/
            hostToBind = protocolConfig.getHost();
            if (provider != null && (hostToBind == null || hostToBind.length() == 0)) {
                hostToBind = provider.getHost();
            }
			/*是否為有效的IP,也就是說在配置檔案中<dubbo:protocol>配置的host不是有效的話則接着按照優先級往下找*/
            if (isInvalidLocalHost(hostToBind)) {
                anyhost = true;
                try {
					/*etc/hosts中hostname-ip映射關系*/
                    hostToBind = InetAddress.getLocalHost().getHostAddress();
                } catch (UnknownHostException e) {
                    logger.warn(e.getMessage(), e);
                }
                if (isInvalidLocalHost(hostToBind)) {
                    if (registryURLs != null && registryURLs.size() > 0) {
                        for (URL registryURL : registryURLs) {
                            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 e) {
                                    }
                                }
                            } catch (Exception e) {
                                logger.warn(e.getMessage(), e);
                            }
                        }
                    }
                    if (isInvalidLocalHost(hostToBind)) {
						/*周遊本地網卡,傳回第一個合理的IP*/
                        hostToBind = getLocalHost();
                    }
                }
            }
        }

        map.put(Constants.BIND_IP_KEY, hostToBind);

        /* registry ip,預設不作為bind ip*/
        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預設作為registry ip*/
            hostToRegistry = hostToBind;
        }

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

        return hostToRegistry;
    }

    /**
     * provider注冊&監聽端口,注冊與監聽port可獨立配置
     * 配置優先級:啟動環境變量 -> java指令參數-D -> protocol配置檔案port屬性配置 -> 協定預設端口
     *
     * @param protocolConfig
     * @param name
     * @return
     */
    private Integer findConfigedPorts(ProtocolConfig protocolConfig, String name, Map<String, String> map) {
        Integer portToBind = null;

        /* 解析環境變量配置的bind port*/
        String port = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_BIND);
        portToBind = parsePort(port);

        /* 如未通過環境變量配置bind port,則繼續按優先級查找*/
        if (portToBind == null) {
            portToBind = protocolConfig.getPort();
            if (provider != null && (portToBind == null || portToBind == 0)) {
                portToBind = provider.getPort();
            }
            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);
            }
        }

        /* 記錄bind port,作為url的key*/
        map.put(Constants.BIND_PORT_KEY, String.valueOf(portToBind));

        /* registry port,預設不作為bind port*/
        String portToRegistryStr = getValueFromConfig(protocolConfig, Constants.DUBBO_PORT_TO_REGISTRY);
        Integer portToRegistry = parsePort(portToRegistryStr);
        if (portToRegistry == null) {
            portToRegistry = portToBind;
        }

        return portToRegistry;
    }
           

繼續閱讀