dubbo源码分析三:consumer注册及生成代理对象
本章我们将分析一下consumer向注册中心注册,并获取服务端相应的信息,根据这些信息生产代理对象的过程和源码。
1.类图
上图展示了部分消费者注册及生成代理对象过程中需要使用到的类和接口,其中:
spring适配涉及到的类:DubboNamespaceHandler、DubboBeanDefinitionParser、ReferenceBean;
配置信息存储:ReferenceConfig、RegistryConfig、MonitorConfig、ProtocolConfig、ConsumerConfig等;
应用协议:Protocol、DubboProtocol、HessianProtocol、ThriftProtocol、RmiProtocol、AbstractProxyProtocol、AbstractProtocol等;
注册相关:RegistryProtocol、RegistryFactory、Registry、ZookeeperRegistryFactory、ZookeeperRegistry等
代理和集群相关:Proxy、JdcProxyFactory、AbstractProxyFactory、InvokerInvocationHandler、Cluster、FailoverCluster、FailoverClusterInvoker、AbstractClusterInvoker、Invoker等;
2.时序图
我们通过时序图来分析一下在consumer注册及生产代理对象的过程中,上面的类是如何串联在一起的:
a.spring容器通过DubboBeanDefinitionParser类的对象来解析xml文件中的标签,生成ReferenceConfig等配置对象;
b.ReferenceConfig的init()等方法被调用;
c.通过spi机制确定Protocol接口的实现对象为RegistryProtocol的对象,调用它的refer()方法;
d.通过spi机制确定RegistryFactory接口的实现对象为ZookeeperRegistryFactory,调用它的getRegistry()方法,生产ZookeeperRegistry对象;
e.调用RegistryProtocol对象的doRefer()方法后,并调用FailoverCluster的join()方法,生成FailoverClusterInvoker的对象;
f.调用JdkProxyFactory的getProxy()方法,生成consumer使用接口的代理对象。
3.核心代码
a.ReferenceConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | private void init() { if (initialized) { //判断是否初始化完毕 return ; } initialized = true ; if (interfaceName == null || interfaceName.length() == 0 ) { throw new IllegalStateException( "<dubbo:reference interface=\"\" /> interface not allow null!" ); } // 获取消费者全局配置 checkDefault(); //检查 appendProperties( this ); if (getGeneric() == null && getConsumer() != null ) { setGeneric(getConsumer().getGeneric()); } if (ProtocolUtils.isGeneric(getGeneric())) { interfaceClass = GenericService. class ; } else { try { interfaceClass = Class.forName(interfaceName, true , Thread.currentThread() .getContextClassLoader()); } catch (ClassNotFoundException e) { throw new IllegalStateException(e.getMessage(), e); } checkInterfaceAndMethods(interfaceClass, methods); } String resolve = System.getProperty(interfaceName); String resolveFile = null ; if (resolve == null || resolve.length() == 0 ) { resolveFile = System.getProperty( "dubbo.resolve.file" ); if (resolveFile == null || resolveFile.length() == 0 ) { File userResolveFile = new File( new File(System.getProperty( "user.home" )), "dubbo-resolve.properties" ); if (userResolveFile.exists()) { resolveFile = userResolveFile.getAbsolutePath(); } } if (resolveFile != null && resolveFile.length() > 0 ) { Properties properties = new Properties(); FileInputStream fis = null ; try { fis = new FileInputStream( new File(resolveFile)); properties.load(fis); } catch (IOException e) { throw new IllegalStateException( "Unload " + resolveFile + ", cause: " + e.getMessage(), e); } finally { try { if ( null != fis) fis.close(); } catch (IOException e) { logger.warn(e.getMessage(), e); } } resolve = properties.getProperty(interfaceName); } } if (resolve != null && resolve.length() > 0 ) { url = resolve; if (logger.isWarnEnabled()) { if (resolveFile != null && resolveFile.length() > 0 ) { logger.warn( "Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service." ); } else { logger.warn( "Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service." ); } } } if (consumer != null ) { if (application == null ) { application = consumer.getApplication(); } if (module == null ) { module = consumer.getModule(); } if (registries == null ) { registries = consumer.getRegistries(); //获取注册信息 } if (monitor == null ) { monitor = consumer.getMonitor(); //获取监控信息 } } 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(); } } checkApplication(); checkStubAndMock(interfaceClass); Map<String, String> map = new HashMap<String, String>(); Map<Object, Object> attributes = new HashMap<Object, Object>(); map.put(Constants.SIDE_KEY, Constants.CONSUMER_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())); } if (! isGeneric()) { 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)), "," )); } } map.put(Constants.INTERFACE_KEY, interfaceName); appendParameters(map, application); appendParameters(map, module); appendParameters(map, consumer, Constants.DEFAULT_KEY); appendParameters(map, this ); String prifix = StringUtils.getServiceKey(map); 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" ); } } appendAttributes(attributes, method, prifix + "." + method.getName()); checkAndConvertImplicitConfig(method, map, attributes); } } //attributes通过系统context进行存储. StaticContext.getSystemContext().putAll(attributes); ref = createProxy(map); //获取代理对象 } private T createProxy(Map<String, String> map) { URL tmpUrl = new URL( "temp" , "localhost" , 0 , map); final boolean isJvmRefer; if (isInjvm() == null ) { if (url != null && url.length() > 0 ) { //指定URL的情况下,不做本地引用 isJvmRefer = false ; } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { //默认情况下如果本地有服务暴露,则引用本地服务. isJvmRefer = true ; } else { isJvmRefer = false ; } } else { isJvmRefer = isInjvm().booleanValue(); } if (isJvmRefer) { URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0 , interfaceClass.getName()).addParameters(map); invoker = refprotocol.refer(interfaceClass, url); //获取invoker对象 if (logger.isInfoEnabled()) { logger.info( "Using injvm service " + interfaceClass.getName()); } } else { if (url != null && url.length() > 0 ) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url); if (us != null && us.length > 0 ) { for (String u : us) { URL url = URL.valueOf(u); if (url.getPath() == null || url.getPath().length() == 0 ) { url = url.setPath(interfaceName); } if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); } else { urls.add(ClusterUtils.mergeUrl(url, map)); } } } } else { // 通过注册中心配置拼装URL List<URL> us = loadRegistries( false ); if (us != null && us.size() > 0 ) { for (URL u : us) { URL monitorUrl = loadMonitor(u); if (monitorUrl != null ) { map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString())); } urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); } } if (urls == null || urls.size() == 0 ) { throw new IllegalStateException( "No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config." ); } } for (URL invo : urls){ System.out.println( "invoker's url : " +invo.toFullString()); } if (urls.size() == 1 ) { invoker = refprotocol.refer(interfaceClass, urls.get( 0 )); //获取invoker对象 } else { List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null ; for (URL url : urls) { invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; // 用了最后一个registry url } } if (registryURL != null ) { // 有 注册中心协议的URL // 对有注册中心的Cluster 只用 AvailableCluster URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); invoker = cluster.join( new StaticDirectory(u, invokers)); } else { // 不是 注册中心的URL invoker = cluster.join( new StaticDirectory(invokers)); } } } System.out.println( "real invoker's url :" +invoker.getUrl().toFullString()); Boolean c = check; if (c == null && consumer != null ) { c = consumer.isCheck(); } if (c == null ) { c = true ; // default true } if (c && ! invoker.isAvailable()) { throw new IllegalStateException( "Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/" ) + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); } if (logger.isInfoEnabled()) { logger.info( "Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); } // 创建服务代理 return (T) proxyFactory.getProxy(invoker); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?