轉載:http://blog.itpub.net/70000181/viewspace-2774479/
-
服務容器負責啓動,加載,運行服務提供者。
-
服務提供者在啓動時,向註冊中心註冊自己提供的服務。
-
服務消費者在啓動時,向註冊中心訂閱自己所需的服務。
-
註冊中心返回服務提供者地址列表給消費者,如果有變更,註冊中心將基於長連接推送變更數據給消費者。
-
服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,如果調用失敗,再選另一臺調用。
-
服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心。
-
dubbo-common:公共邏輯模塊: 包括Util類和通用模型
-
dubbo-remoting 遠程通信模塊: 相當於dubbo協議的實現,如果RPC使用RMI協議則不需要使用此包
-
dubbo-rpc 遠程調用模塊: 抽象各種協議,以及動態代理,包含一對一的調用,不關心集羣的原理。
-
dubbo-cluster 集羣模塊: 將多個服務提供方僞裝成一個提供方,包括負載均衡,容錯,路由等,集羣的地址列表可以是靜態配置的,也可以是註冊中心下發的.
-
dubbo-registry 註冊中心模塊: 基於註冊中心下發的集羣方式,以及對各種註冊中心的抽象
-
dubbo-monitor 監控模塊: 統計服務調用次數,調用時間,調用鏈跟蹤的服務.
-
dubbo-config 配置模塊: 是dubbo對外的api,用戶通過config使用dubbo,隱藏dubbo所有細節
-
dubbo-container 容器模塊: 是一個standlone的容器,以簡單的main加載spring啓動,因爲服務通常不需要Tomcat/Jboss等web容器的特性,沒必要用web容器去加載服務.
-
圖中左邊淡藍背景的爲服務消費方使用的接口,右邊淡綠色背景的爲服務提供方使用的接口,位於中軸線上的爲雙方都用到的接口。
-
圖中從下至上分爲十層,各層均爲單向依賴,每一層都可以剝離上層被複用,其中,Service 和Config 層爲API,其它各層均爲SPI。
-
圖中綠色小塊的爲擴展接口,藍色小塊爲實現類,圖中只顯示用於關聯各層的實現類。
-
圖中藍色虛線爲初始化過程,即啓動時組裝鏈,紅色實線爲方法調用過程,即運行時調時鏈,紫色三角箭頭爲繼承,可以把子類看作父類的同一個節點,線上的文字爲調用的方法。
-
config 配置層:對外配置接口,以 ServiceConfig , ReferenceConfig 爲中心,可以直接初始化配置類,也可以通過spring 解析配置生成配置類
-
proxy 服務代理層:服務接口透明代理,生成服務的客戶端Stub 和服務器端Skeleton, 以ServiceProxy 爲中心,擴展接口爲 ProxyFactory
-
registry 註冊中心層:封裝服務地址的註冊與發現,以服務URL 爲中心,擴展接口爲RegistryFactory , Registry , RegistryService
-
cluster 路由層:封裝多個提供者的路由及負載均衡,並橋接註冊中心,以 Invoker 爲中心,擴展接口爲 Cluster , Directory , Router , LoadBalance
-
monitor 監控層:RPC 調用次數和調用時間監控,以 Statistics 爲中心,擴展接口爲MonitorFactory , Monitor , MonitorService
-
protocol 遠程調用層:封裝RPC 調用,以 Invocation , Result 爲中心,擴展接口爲Protocol , Invoker , Exporter
-
exchange 信息交換層:封裝請求響應模式,同步轉異步,以 Request , Response 爲中心,擴展接口爲 Exchanger , ExchangeChannel , ExchangeClient , ExchangeServer
-
transport 網絡傳輸層:抽象mina 和netty 爲統一接口,以 Message 爲中心,擴展接口爲Channel , Transporter , Client , Server , Codec
-
serialize 數據序列化層:可複用的一些工具,擴展接口爲 Serialization , ObjectInput ,ObjectOutput , ThreadPool
package com.laowang; /** * @author 原 * @date 2021/3/27 * @since 1.0 **/ public interface User { String showName(); }
package com.laowang.impl; import com.laowang.User; /** * @author 原 * @date 2021/3/27 * @since 1.0 **/ public class Student implements User { @Override public String showName() { System.out.println("my name is laowang"); return null; } }package com.laowang.impl; import com.laowang.User; /** * @author 原 * @date 2021/3/27 * @since 1.0 **/ public class Teacher implements User { @Override public String showName() { System.out.println("my name is zhangsan"); return null; } }
package com.laowang; import java.util.ServiceLoader; /** * @author 原 * @date 2021/3/27 * @since 1.0 **/ public class SpiTest { public static void main(String[] args) { ServiceLoader<User> serviceLoader = ServiceLoader.load(User.class); serviceLoader.forEach(User::showName); } }
optimusPrime = org.apache.spi.OptimusPrime bumblebee = org.apache.spi.Bumblebee
@SPI public interface Robot { void sayHello(); }
public class DubboSPITest { @Test public void sayHello() throws Exception { ExtensionLoader<Robot> extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class); Robot optimusPrime = extensionLoader.getExtension("optimusPrime"); optimusPrime.sayHello(); Robot bumblebee = extensionLoader.getExtension("bumblebee"); bumblebee.sayHello(); } }
public T getExtension(String name) { if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("Extension name == null"); } if ("true".equals(name)) { // 獲取默認的拓展實現類 return getDefaultExtension(); } // Holder,顧名思義,用於持有目標對象 就是從容器中獲取,如果沒有直接new一個Holder Holder<Object> holder = getOrCreateHolder(name); //獲取目標對象實例 Object instance = holder.get(); // 如果目標對象實例爲null 就需要通過雙重檢查創建實例 if (instance == null) { synchronized (holder) { instance = holder.get(); if (instance == null) { // 創建拓展實例 instance = createExtension(name); // 設置實例到 holder 中 holder.set(instance); } } } return (T) instance; }
private T createExtension(String name) { // 從配置文件中加載所有的拓展類,可得到“配置項名稱”到“配置類”的映射關係表 Class<?> clazz = getExtensionClasses().get(name); if (clazz == null) { throw findException(name); } try { //從容器中獲取對應的實例對象 如果不存在就通過反射創建 T instance = (T) EXTENSION_INSTANCES.get(clazz); if (instance == null) { // 通過反射創建實例 EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); instance = (T) EXTENSION_INSTANCES.get(clazz); } // 向實例中注入依賴 下面是IOC和AOP的實現 injectExtension(instance); Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (CollectionUtils.isNotEmpty(wrapperClasses)) { // 循環創建 Wrapper 實例 for (Class<?> wrapperClass : wrapperClasses) { // 將當前 instance 作爲參數傳給 Wrapper 的構造方法,並通過反射創建Wrapper 實例。 // 然後向 Wrapper 實例中注入依賴,最後將 Wrapper 實例再次賦值給instance 變量 instance = injectExtension( (T) wrapperClass.getConstructor(type).newInstance(instance)); } }
-
通過getExtensionClasses 獲取所有的拓展類
-
通過反射創建拓展對象
-
向拓展對象中注入依賴
-
將拓展對象包裹在相應的Wrapper 對象中
getExtension(String name) #根據key獲取拓展對象 -->createExtension(String name) #創建拓展實例 -->getExtensionClasses #根據路徑獲取所有的拓展類 -->loadExtensionClasses #加載拓展類 -->cacheDefaultExtensionName #解析@SPI註解 -->loadDirectory #方法加載指定文件夾配置文件 -->loadResource #加載資源 -->loadClass #加載類,並通過 loadClass 方法對類進行緩存
private T injectExtension(T instance) { try { if (objectFactory != null) { //獲取實例的所有方法 for (Method method : instance.getClass().getMethods()) { //isSetter做的事:檢測方法是否以 set 開頭,且方法僅有一個參數,且方法訪問級別爲 public if (isSetter(method)) { /** * Check {@link DisableInject} to see if we need auto injection for this property */ if (method.getAnnotation(DisableInject.class) != null) { continue; } Class<?> pt = method.getParameterTypes()[0]; if (ReflectUtils.isPrimitives(pt)) { continue; } try { String property = getSetterProperty(method); //獲取依賴對象 Object object = objectFactory.getExtension(pt, property); if (object != null) { //設置屬性 method.invoke(instance, object); } } catch (Exception e) { logger.error("Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": " + e.getMessage(), e); } } } } } catch (Exception e) { logger.error(e.getMessage(), e); } return instance; }
//獲取所有需要包裝的類 Set<Class<?>> wrapperClasses = cachedWrapperClasses;
private Set<Class<?>> cachedWrapperClasses;
/** * cache wrapper class * <p> * like: ProtocolFilterWrapper, ProtocolListenerWrapper */ private void cacheWrapperClass(Class<?> clazz) { if (cachedWrapperClasses == null) { cachedWrapperClasses = new ConcurrentHashSet<>(); } cachedWrapperClasses.add(clazz); }
/** * test if clazz is a wrapper class * <p> * which has Constructor with given class type as its only argument */ private boolean isWrapperClass(Class<?> clazz) { try { clazz.getConstructor(type); return true; } catch (NoSuchMethodException e) { return false; } }
-
首先Dubbo 會爲拓展接口生成具有代理功能的代碼;
-
通過javassist 或jdk 編譯這段代碼,得到Class 類;
-
通過反射創建代理類;
-
在代理類中,通過URL對象的參數來確定到底調用哪個實現類;
/** * Javassist是一個開源的分析、編輯和創建Java字節碼的類庫 * 能動態改變類的結構,或者動態生成類 */ public class CompilerByJavassist { public static void main(String[] args) throws Exception { // ClassPool:class對象容器 ClassPool pool = ClassPool.getDefault(); // 通過ClassPool生成一個User類 CtClass ctClass = pool.makeClass("com.itheima.domain.User"); // 添加屬性 -- private String username CtField enameField = new CtField(pool.getCtClass("java.lang.String"), "username", ctClass); enameField.setModifiers(Modifier.PRIVATE); ctClass.addField(enameField); // 添加屬性 -- private int age CtField enoField = new CtField(pool.getCtClass("int"), "age", ctClass); enoField.setModifiers(Modifier.PRIVATE); ctClass.addField(enoField); //添加方法 ctClass.addMethod(CtNewMethod.getter("getUsername", enameField)); ctClass.addMethod(CtNewMethod.setter("setUsername", enameField)); ctClass.addMethod(CtNewMethod.getter("getAge", enoField)); ctClass.addMethod(CtNewMethod.setter("setAge", enoField)); // 無參構造器 CtConstructor constructor = new CtConstructor(null, ctClass); constructor.setBody("{}"); ctClass.addConstructor(constructor); // 添加構造函數 //ctClass.addConstructor(new CtConstructor(new CtClass[] {}, ctClass)); CtConstructor ctConstructor = new CtConstructor(new CtClass[] {pool.get(String.class.getName()),CtClass.intType}, ctClass); ctConstructor.setBody("{\n this.username=$1; \n this.age=$2;\n}"); ctClass.addConstructor(ctConstructor); // 添加自定義方法 CtMethod ctMethod = new CtMethod(CtClass.voidType, "printUser",new CtClass[] {}, ctClass); // 爲自定義方法設置修飾符 ctMethod.setModifiers(Modifier.PUBLIC); // 爲自定義方法設置函數體 StringBuffer buffer2 = new StringBuffer(); buffer2.append("{\nSystem.out.println(\"用戶信息如下\");\n") .append("System.out.println(\"用戶名=\"+username);\n") .append("System.out.println(\"年齡=\"+age);\n").append("}"); ctMethod.setBody(buffer2.toString()); ctClass.addMethod(ctMethod); //生成一個class Class<?> clazz = ctClass.toClass(); Constructor cons2 = clazz.getDeclaredConstructor(String.class,Integer.TYPE); Object obj = cons2.newInstance("itheima",20); //反射 執行方法 obj.getClass().getMethod("printUser", new Class[] {}) .invoke(obj, new Object[] {}); // 把生成的class文件寫入文件 byte[] byteArr = ctClass.toBytecode(); FileOutputStream fos = new FileOutputStream(new File("D://User.class")); fos.write(byteArr); fos.close(); } }
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; }
//1、看下extensionLoader的獲取方法 ExtensionLoader<Robot>extensionLoader=ExtensionLoader.getExtensionLoader(Robot.class); //2、最終調用的是ExtensionLoader的構造方法 private ExtensionLoader(Class<?> type) { this.type = type; objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()); } //3、getAdaptiveExtension()看看幹了什麼事 public T getAdaptiveExtension() { //獲取自適應擴展類,如果沒有就開始初始化一個 Object instance = cachedAdaptiveInstance.get(); if (instance == null) { if (createAdaptiveInstanceError == null) { synchronized (cachedAdaptiveInstance) { instance = cachedAdaptiveInstance.get(); if (instance == null) { try { //這裏創建了一個自適應擴展類 instance = createAdaptiveExtension(); cachedAdaptiveInstance.set(instance); } catch (Throwable t) { createAdaptiveInstanceError = t; throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t); } } } } else { throw new IllegalStateException("Failed to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError); } } return (T) instance; } //看看createAdaptiveExtension() private T createAdaptiveExtension() { try { return injectExtension((T) getAdaptiveExtensionClass().newInstance()); } catch (Exception e) { throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e); } } //再進到getAdaptiveExtensionClass() private Class<?> getAdaptiveExtensionClass() { getExtensionClasses(); if (cachedAdaptiveClass != null) { return cachedAdaptiveClass; } return cachedAdaptiveClass = createAdaptiveExtensionClass(); } //繼續追進去createAdaptiveExtensionClass() private Class<?> createAdaptiveExtensionClass() { String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate(); ClassLoader classLoader = findClassLoader(); org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension(); return compiler.compile(code, classLoader); } //看看compiler @SPI("javassist") public interface Compiler { /** * Compile java source code. * * @param code Java source code * @param classLoader classloader * @return Compiled class */ Class<?> compile(String code, ClassLoader classLoader); } //其實到這裏就知道了,通過生成一個類的字符串,再通過javassist生成一個對象
-
Invoker 是實體域,它是Dubbo 的核心模型,其它模型都向它靠擾,或轉換成它,它代表一個可執行體,可向它發起invoke 調用,它有可能是一個本地的實現,也可能是一個遠程的實現,也可能一個集羣實現。在服務提供方,Invoker用於調用服務提供類。在服務消費方,Invoker用於執行遠程調用。
-
Protocol 是服務域,它是Invoker 暴露和引用的主功能入口,它負責Invoker 的生命週期管理。 export:暴露遠程服務 refer:引用遠程服務
-
proxyFactory:獲取一個接口的代理類 getInvoker:針對server端,將服務對象,如DemoServiceImpl包裝成一個Invoker對象 getProxy:針對client端,創建接口的代理對象,例如DemoService的接口。
-
Invocation 是會話域,它持有調用過程中的變量,比如方法名,參數等
@Override public void onApplicationEvent(ContextRefreshedEvent event) { if (!isExported() && !isUnexported()) { if (logger.isInfoEnabled()) { logger.info("The service ready on spring started. service: " + getInterface()); } export(); } }
private void doExportUrls() { //加載配置文件中的所有註冊中心,並且封裝爲dubbo內部的URL對象列表 List<URL> registryURLs = loadRegistries(true); //循環所有協議配置,根據不同的協議,向註冊中心中發起註冊 for (ProtocolConfig protocolConfig : protocols) { String pathKey = URL.buildKey(getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), group, version); ProviderModel providerModel = new ProviderModel(pathKey, ref, interfaceClass); ApplicationModel.initProviderModel(pathKey, providerModel); //服務暴露方法 doExportUrlsFor1Protocol(protocolConfig, registryURLs); } }
... if (!SCOPE_NONE.equalsIgnoreCase(scope)) { //本地暴露,將服務數據記錄到本地JVM中 if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) { exportLocal(url); } //遠程暴露,向註冊中心發送數據 if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) { if (!isOnlyInJvm() && logger.isInfoEnabled()) { logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url); } if (CollectionUtils.isNotEmpty(registryURLs)) { for (URL registryURL : registryURLs) { //if protocol is only injvm ,not register if (LOCAL_PROTOCOL.equalsIgnoreCase(url.getProtocol())) { continue; } url = url.addParameterIfAbsent(DYNAMIC_KEY, registryURL.getParameter(DYNAMIC_KEY)); URL monitorUrl = loadMonitor(registryURL); if (monitorUrl != null) { url = url.addParameterAndEncoded(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 String proxy = url.getParameter(PROXY_KEY); if (StringUtils.isNotEmpty(proxy)) { registryURL = registryURL.addParameter(PROXY_KEY, proxy); } // 爲服務提供類(ref)生成 Invoker Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(EXPORT_KEY, url.toFullString())); // DelegateProviderMetaDataInvoker 用於持有 Invoker 和ServiceConfig DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); // 導出服務,並生成 Exporter Exporter<?> exporter = protocol.export(wrapperInvoker); exporters.add(exporter); } } else { //不存在註冊中心,僅導出服務 .... } /** * @since 2.7.0 * ServiceData Store */ MetadataReportService metadataReportService = null; if ((metadataReportService = getMetadataReportService()) != null) { metadataReportService.publishProvider(url); } } } this.urls.add(url);
@Override public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) { // 爲目標類創建warpper final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type); //創建匿名才invoker對象,並實現doinvoke方法 return new AbstractProxyInvoker<T>(proxy, type, url) { @Override protected Object doInvoke(T proxy, String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Throwable { // 調用 Wrapper 的 invokeMethod 方法,invokeMethod 最終會調用目標方法 return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); } }; }
/** * always export injvm */ private void exportLocal(URL url) { URL local = URLBuilder.from(url) .setProtocol(LOCAL_PROTOCOL) // 設置協議頭爲 injvm .setHost(LOCALHOST_VALUE)//本地ip:127.0.0.1 .setPort(0) .build(); // 創建 Invoker,並導出服務,這裏的 protocol 會在運行時調用 InjvmProtocol 的export 方法 Exporter<?> exporter = protocol.export( proxyFactory.getInvoker(ref, (Class) interfaceClass, local)); exporters.add(exporter); logger.info("Export dubbo service " + interfaceClass.getName() + " to local registry url : " + local); }
@Override public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { return new InjvmExporter<T>(invoker, invoker.getUrl().getServiceKey(), exporterMap); }
@Override public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException { // 獲取註冊中心 URL URL registryUrl = getRegistryUrl(originInvoker); URL providerUrl = getProviderUrl(originInvoker); final URL overrideSubscribeUrl = getSubscribedOverrideUrl(providerUrl); final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker); overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener); providerUrl = overrideUrlWithConfig(providerUrl, overrideSubscribeListener); //導出服務 final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker, providerUrl); // 根據 URL 加載 Registry 實現類,比如 ZookeeperRegistry final Registry registry = getRegistry(originInvoker); //獲取已註冊的服務提供者 URL, final URL registeredProviderUrl = getRegisteredProviderUrl(providerUrl, registryUrl); ProviderInvokerWrapper<T> providerInvokerWrapper = ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registeredProviderUrl); //to judge if we need to delay publish boolean register = registeredProviderUrl.getParameter("register", true); if (register) { // 向註冊中心註冊服務 register(registryUrl, registeredProviderUrl); providerInvokerWrapper.setReg(true); } // 向註冊中心進行訂閱 override 數據 registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener); exporter.setRegisterUrl(registeredProviderUrl); exporter.setSubscribeUrl(overrideSubscribeUrl); // 創建並返回 DestroyableExporter return new DestroyableExporter<>(exporter); }
-
調用doLocalExport 導出服務
-
向註冊中心註冊服務
-
向註冊中心進行訂閱override 數據
-
創建並返回DestroyableExporter
private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> originInvoker, URL providerUrl) { String key = getCacheKey(originInvoker); return (ExporterChangeableWrapper<T>) bounds.computeIfAbsent(key, s -> { Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, providerUrl); //protocol和配置的協議相關(dubbo:DubboProtocol) return new ExporterChangeableWrapper<>((Exporter<T>) protocol.export(invokerDelegate), originInvoker); }); }
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { URL url = invoker.getUrl(); // export service.獲取服務標識,理解成服務座標也行。由服務組名,服務名,服務版本號以及端口組成。比如:demoGroup/com.alibaba.dubbo.demo.DemoService:1.0.1:20880 String key = serviceKey(url); //創建DubboExporter DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //key:接口 (DemoService) //export an stub service for dispatching event Boolean isStubSupportEvent = url.getParameter(STUB_EVENT_KEY, DEFAULT_STUB_EVENT); Boolean isCallbackservice = url.getParameter(IS_CALLBACK_SERVICE, false); if (isStubSupportEvent && !isCallbackservice) { String stubServiceMethods = url.getParameter(STUB_EVENT_METHODS_KEY); if (stubServiceMethods == null || stubServiceMethods.length() == 0) { if (logger.isWarnEnabled()) { logger.warn(new IllegalStateException("consumer [" + url.getParameter(INTERFACE_KEY) + "], has set stubproxy support event ,but no stub methods founded.")); } } else { stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods); } } //啓動服務 openServer(url); //優化序列器 optimizeSerialization(url); return exporter; }
private void openServer(URL url) { // find server. String key = url.getAddress(); //client can export a service which's only for server to invoke boolean isServer = url.getParameter(IS_SERVER_KEY, true); if (isServer) { //訪問緩存 ExchangeServer server = serverMap.get(key); if (server == null) { synchronized (this) { server = serverMap.get(key); if (server == null) { //創建服務器實例 serverMap.put(key, createServer(url)); } } } else { // server supports reset, use together with override server.reset(url); } } }
private ExchangeServer createServer(URL url) { url = URLBuilder.from(url) // send readonly event when server closes, it's enabled by default .addParameterIfAbsent(CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString()) // enable heartbeat by default .addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT)) .addParameter(CODEC_KEY, DubboCodec.NAME) .build(); String str = url.getParameter(SERVER_KEY, DEFAULT_REMOTING_SERVER); // 通過 SPI 檢測是否存在 server 參數所代表的 Transporter 拓展,不存在則拋出異常 if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) { throw new RpcException("Unsupported server type: " + str + ", url: " + url); } ExchangeServer server; try { // 創建 ExchangeServer server = Exchangers.bind(url, requestHandler); } catch (RemotingException e) { throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e); } // 獲取 client 參數,可指定 netty,mina str = url.getParameter(CLIENT_KEY); if (str != null && str.length() > 0) { // 獲取所有的 Transporter 實現類名稱集合,比如 supportedTypes = [netty, mina] Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(); // 檢測當前 Dubbo 所支持的 Transporter 實現類名稱列表中, // 是否包含 client 所表示的 Transporter,若不包含,則拋出異常 if (!supportedTypes.contains(str)) { throw new RpcException("Unsupported client type: " + str); } } return server; }
public static ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { if (url == null) { throw new IllegalArgumentException("url == null"); } if (handler == null) { throw new IllegalArgumentException("handler == null"); } url = url.addParameterIfAbsent(Constants.CODEC_KEY, "exchange"); // 獲取 Exchanger,默認爲 HeaderExchanger。 // 緊接着調用 HeaderExchanger 的 bind 方法創建 ExchangeServer 實例 return getExchanger(url).bind(url, handler); }
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException { // 創建 HeaderExchangeServer 實例,該方法包含了多個邏輯,分別如下: // 1. new HeaderExchangeHandler(handler) // 2. new DecodeHandler(new HeaderExchangeHandler(handler)) // 3. Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))) return new HeaderExchangeServer(Transporters.bind(url, new ChannelHandler[]{new DecodeHandler(new HeaderExchangeHandler(handler))})); }
public static Server bind(URL url, ChannelHandler... handlers) throws RemotingException { if (url == null) { throw new IllegalArgumentException("url == null"); } else if (handlers != null && handlers.length != 0) { Object handler; if (handlers.length == 1) { handler = handlers[0]; } else { // 如果 handlers 元素數量大於1,則創建 ChannelHandler 分發器 handler = new ChannelHandlerDispatcher(handlers); } // 獲取自適應 Transporter 實例,並調用實例方法 return getTransporter().bind(url, (ChannelHandler)handler); } else { throw new IllegalArgumentException("handlers == null"); } }
public void register(URL registryUrl, URL registeredProviderUrl) { //獲得註冊中心實例 Registry registry = registryFactory.getRegistry(registryUrl); //進行註冊 registry.register(registeredProviderUrl); }
@Override public Registry getRegistry(URL url) { url = URLBuilder.from(url) .setPath(RegistryService.class.getName()) .addParameter(INTERFACE_KEY, RegistryService.class.getName()) .removeParameters(EXPORT_KEY, REFER_KEY) .build(); String key = url.toServiceStringWithoutResolving(); // Lock the registry access process to ensure a single instance of the registry LOCK.lock(); try { Registry registry = REGISTRIES.get(key); if (registry != null) { return registry; } //create registry by spi/ioc registry = createRegistry(url); if (registry == null) { throw new IllegalStateException("Can not create registry " + url); } REGISTRIES.put(key, registry); return registry; } finally { // Release the lock LOCK.unlock(); } }
@Override public Registry createRegistry(URL url) { return new ZookeeperRegistry(url, zookeeperTransporter); }public ZookeeperRegistry(URL url, ZookeeperTransporter zookeeperTransporter) { super(url); if (url.isAnyHost()) { throw new IllegalStateException("registry address == null"); } //// 獲取組名,默認爲 dubbo String group = url.getParameter(GROUP_KEY, DEFAULT_ROOT); if (!group.startsWith(PATH_SEPARATOR)) { group = PATH_SEPARATOR + group; } this.root = group; // 創建 Zookeeper 客戶端,默認爲 CuratorZookeeperTransporter zkClient = zookeeperTransporter.connect(url); // 添加狀態監聽器 zkClient.addStateListener(state -> { if (state == StateListener.RECONNECTED) { try { recover(); } catch (Exception e) { logger.error(e.getMessage(), e); } } }); }
public void doRegister(URL url) { try { // 通過 Zookeeper 客戶端創建節點,節點路徑由 toUrlPath 方法生成,路徑格式如下: // /${group}/${serviceInterface}/providers/${url} // 比如 /dubbo/org.apache.dubbo.DemoService/providers/dubbo%3A%2F%2F127.0.0.1...... zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true)); } catch (Throwable e) { throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } }@Override public void create(String path, boolean ephemeral) { if (!ephemeral) { // 如果要創建的節點類型非臨時節點,那麼這裏要檢測節點是否存在 if (checkExists(path)) { return; } } int i = path.lastIndexOf('/'); if (i > 0) { // 遞歸創建上一級路徑 create(path.substring(0, i), false); } // 根據 ephemeral 的值創建臨時或持久節點 if (ephemeral) { createEphemeral(path); } else { createPersistent(path); } }
-
在有註冊中心,需要註冊提供者地址的情況下,ServiceConfig 解析出的URL 格式爲:registry:// registry-host/org.apache.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/{服務名}/{版本號}")
-
基於Dubbo SPI 的自適應機制,通過URL registry:// 協議頭識別,就調用RegistryProtocol#export() 方法
-
將具體的服務類名,比如 DubboServiceRegistryImpl ,通過ProxyFactory 包裝成Invoker 實例
-
調用doLocalExport 方法,使用DubboProtocol 將Invoker 轉化爲Exporter 實例,並打開Netty 服務端監聽客戶請求
-
創建Registry 實例,連接Zookeeper,並在服務節點下寫入提供者的URL 地址,註冊服務
-
向註冊中心訂閱override 數據,並返回一個Exporter 實例
-
根據URL 格式中的 "dubbo://service-host/{服務名}/{版本號}" 中協議頭 dubbo:// 識別,調用DubboProtocol#export()方法,開發服務端口
-
RegistryProtocol#export() 返回的Exporter 實例存放到ServiceConfig 的 List<Exporter>exporters 中
-