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(); } }
<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())); } //<8>反射获取application所有公共的get方法 以及parameter配置 封装到map appendParameters(map, application); //<8>反射获取moule所有公共的get方法 以及parameter配置 封装到map appendParameters(map, module); //<8>反射获取provider所有公共的get方法 以及parameter配置 封装到map appendParameters(map, provider, Constants.DEFAULT_KEY); //<8>反射获取provider所有公共的get方法 以及parameter配置 封装到map appendParameters(map, protocolConfig); //<8>反射获取当前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"); } }
走到这里就是分水岭了 采用什么样的协议暴露服务
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!