dubbo-源码阅读之服务发布
原理
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-源码阅读之服务发布的更多相关文章
- dubbo 源码学习1 服务发布机制
1.源码版本:2.6.1 源码demo中采用的是xml式的发布方式,在dubbo的 DubboNamespaceHandler 中定义了Spring Framework 的扩展标签,即 <dub ...
- dubbo源码阅读之服务导出
dubbo服务导出 常见的使用dubbo的方式就是通过spring配置文件进行配置.例如下面这样 <?xml version="1.0" encoding="UTF ...
- dubbo源码阅读之服务目录
服务目录 服务目录对应的接口是Directory,这个接口里主要的方法是 List<Invoker<T>> list(Invocation invocation) throws ...
- dubbo源码阅读之服务引入
服务引入 服务引入使用reference标签来对要引入的服务进行配置,包括服务的接口 ,名称,init,check等等配置属性. 在DubboNamespaceHandler中,我们可以看到refer ...
- 【Dubbo源码阅读系列】服务暴露之远程暴露
引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...
- 【Dubbo源码阅读系列】服务暴露之本地暴露
在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...
- 【Dubbo源码阅读系列】之远程服务调用(上)
今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...
- Dubbo源码学习之-服务导出
前言 忙的时候,会埋怨学习的时间太少,缺少个人的空间,于是会争分夺秒的工作.学习.而一旦繁忙的时候过去,有时间了之后,整个人又会不自觉的陷入一种懒散的状态中,时间也显得不那么重要了,随便就可以浪费掉几 ...
- 【Dubbo源码阅读系列】之 Dubbo SPI 机制
最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...
- Dubbo源码阅读顺序
转载: https://blog.csdn.net/heroqiang/article/details/85340958 Dubbo源码解析之配置解析篇,主要内容是<dubbo:service/ ...
随机推荐
- HTML中的img标签属性
<img>标签 标签用于插入图片.它是单独使用的,没有闭合标签. <img src="https://fakeimg.pl/350x200/ff0000,128/000,2 ...
- Base64和3DES算法
Base64加密算法 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,可用于在HTTP环境下传递较长的标识信息.它的优点是算法效率高,编码出来的结果比较简短,同时也具有不可读性. ...
- 【dart学习】-- Dart之异步编程
一,概述 编程中的代码执行,通常分为同步与异步两种. 同步:简单说,同步就是按照代码的编写顺序,从上到下依次执行,这也是最简单的我们最常接触的一种形式.但是同步代码的缺点也显而易见,如果其中某一行或几 ...
- SCP-Py-002
项目编号:Py-002 项目等级:EuclidKeter 特殊收容措施: Py-002-1目前被映射在Researcher Kevin的服务器位于Site-Pyproject地下防无线电渗透室且被切断 ...
- BZOJ 1778: [Usaco2010 Hol]Dotp 驱逐猪猡(高斯消元+期望dp)
传送门 解题思路 设\(f(x)\)表示到\(x\)这个点的期望次数,那么转移方程为\(f(x)=\sum\frac{f(u)*(1 - \frac{p}{q})}{deg(u)}\),其中\(u\) ...
- LOJ 2554 「CTSC2018」青蕈领主——结论(思路)+分治FFT
题目:https://loj.ac/problem/2554 一个“连续”的区间必然是一个排列.所有 r 不同的.len 最长的“连续”区间只有包含.相离,不会相交,不然整个是一个“连续”区间. 只有 ...
- ip协议,IP,子网掩码,ping命令是什么
ip协议: 定网络地址的协议叫ip协议,它定义的地址称之为ip地址,广泛采用的v4版本即ipv4,它规定网络地址由32位2进制表示 IP地址:是给每个连接在Internet上的主机分配的一个32bit ...
- (2)C++基本类型
一.整形 short .int. long. long long sizeof查看类型所占的字节数 cout << sizeof(short)<<endl;//2 字节 cou ...
- SPSS输出的结果都要写到文章中吗
SPSS输出的结果都要写到文章中吗 经常有人问到,SPSS输出的结果都要写到文章中吗?文章中应该写什么呢?比如,均值.中位数.众数.标准差.百分位数.最小值.最大值等等,都要出现在文章中吗?洋洋洒洒那 ...
- day 62.3 Django基础八之cookie和session
Django基础八之cookie和session 本节目录 一 会话跟踪 二 cookie 三 django中操作cookie 四 session 五 django中操作session 六 xxx ...