dubbo原始碼:dubbo服務暴露過程
阿新 • • 發佈:2018-12-19
-
dubbo標籤解析
spring通過在DubboNamespaceHandler註冊dubbo解析器DubboBeanDefinitionParser,在載入Bean的時候同時解析dubbo標籤並載入dubbo標籤解析後的Bean
-
暴露dubbo服務
dubbo標籤解析完成後,會把dubbo:service標籤解析解析成型別為ServiceBean的RootBeanDefinition,並進行例項化,
<!--定義了提供方應用資訊,用於計算依賴關係;在 dubbo-admin 或 dubbo-monitor 會顯示這個名字,方便辨識--> <dubbo:application
由於ServiceBean實現了InitializingBean和ApplicationListener介面,一個是在類初始化完成後呼叫afterPropertiesSet方法,一個在Spring容器初始化完成後會呼叫onApplicationEvent方法(呼叫參考bean的載入過程),即重要的就是這兩個方法,這兩個方法
public void afterPropertiesSet() throws Exception { // ServiceConfig根據dubbo:provider標籤設定provider // ServiceConfig根據dubbo:application標籤設定應用資訊配置 // SerivceConfig根據dubbo:module標籤設定模組資訊配置 // SerivceConfig設定註冊中心 // SerivceConfig根據dubbo:monitor標籤設定監控中心配置 // SerivceConfig設定服務提供者協議配置 if (! isDelay()) { export(); } } public void onApplicationEvent(ApplicationEvent event) { if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) { if (isDelay() && ! isExported() && ! isUnexported()) { export(); } } } public synchronized void export() { //省略程式碼,從provider中獲取delay if (delay != null && delay > 0) { Thread thread = new Thread(new Runnable() { public void run() { // 睡delay時間 Thread.sleep(delay); // 暴露服務 doExport(); } }); thread.setDaemon(true); thread.setName("DelayExportServiceThread"); thread.start(); } else { // 沒有設定delay,直接暴露服務 doExport(); } } protected synchronized void doExport() { // 省略大部分校驗程式碼...... doExportUrls(); } private void doExportUrls() { List<URL> registryURLs = loadRegistries(true); // 按照不同的Protocol如(dubbo,injvm)來暴露服務 for (ProtocolConfig protocolConfig : protocols) { // 1.如果協議型別為null,則預設為dubbo協議 String name = protocolConfig.getName(); if (name == null || name.length() == 0) { name = "dubbo"; } // 2.獲取主機名host(省略程式碼) // 3.獲取埠號port(省略程式碼) // 4.引數設定到map中 Map<String, String> map = new HashMap<String, String>(); // URL中的side屬性,有兩個值,一個provider,一個consumer,暴露服務的時候為provider map.put(Constants.SIDE_KEY, Constants.PROVIDER_SIDE); // dubbo的版本號 url中的dubbo map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); // url中的timestamp map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); //url中的pid if (ConfigUtils.getPid() > 0) { map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); } //從其他引數中獲取引數 appendParameters(map, application); appendParameters(map, module); appendParameters(map, provider, Constants.DEFAULT_KEY); appendParameters(map, protocolConfig); appendParameters(map, this); // 從暴露的方法配置資訊中獲取引數和值(程式碼省略) // 通用服務介面和非通用服務介面的引數 if (generic) { // 通用服務介面 map.put("generic", String.valueOf(true)); map.put("methods", Constants.ANY_VALUE); } else { String revision = Version.getVersion(interfaceClass, version); if (revision != null && revision.length() > 0) { map.put("revision", revision); } map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(Wrapper.getWrapper(interfaceClass).getDeclaredMethodNames())), ",")); } //5.token 臨牌校驗(程式碼省略) //6.injvm協議處理(程式碼省略) //7.匯出服務 // 獲取上下文路徑 String contextPath = protocolConfig.getContextpath(); if ((contextPath == null || contextPath.length() == 0) && provider != null) { contextPath = provider.getContextpath(); } // 組裝URL URL url = new URL(name, host, port, (contextPath == null || contextPath.length() == 0 ? "" : contextPath + "/") + path, map); // 如果url使用的協議存在擴充套件,呼叫對應的擴充套件來修改原url(程式碼省略) String scope = url.getParameter(Constants.SCOPE_KEY); //配置為none不暴露 if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) { //配置不是remote的情況下做本地暴露 (配置為remote,則表示只暴露遠端服務) if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) { exportLocal(url); } //如果配置不是local則暴露為遠端服務.(配置為local,則表示只暴露本地服務) if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){ if (registryURLs != null && registryURLs.size() > 0 && url.getParameter("register", true)) { for (URL registryURL : registryURLs) { // 省略部分程式碼 // 通過代理工廠將ref物件轉化成invoker物件 Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString())); // 暴露服務(DubboProtocol來暴露服務,) Exporter<?> exporter = protocol.export(invoker); //一個服務可能有多個提供者,儲存在一起 exporters.add(exporter); } } else { Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url); Exporter<?> exporter = protocol.export(invoker); exporters.add(exporter); } } } this.urls.add(url); } }
注:<dubbo:reference…scope=“remote”/>,scope為remote表示引用遠端服務;為local表示引用本地服務;
DubboProtocol中暴露服務:
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { // 獲取URL URL url = invoker.getUrl(); // export service. String key = serviceKey(url); DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap); exporterMap.put(key, exporter); //export an stub service for dispaching event(程式碼省略) openServer(url); return exporter; } private void openServer(URL url) { // 查詢服務 String key = url.getAddress(); //client 也可以暴露一個只有server可以呼叫的服務,所以需要判斷是否是服務端 boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true); if (isServer) { ExchangeServer server = serverMap.get(key); if (server == null) { //如果服務不存在,建立服務 serverMap.put(key, getServer(url)); } else { //server支援reset,配合override功能使用 server.reset(url); } } } private ExchangeServer getServer(URL url) { // 忽略部分程式碼 ExchangeServer server; server = Exchangers.bind(url, requestHandler); return server; } // 上述最終會呼叫到Netty public class NettyTransporter implements Transporter { public static final String NAME = "netty"; public Server bind(URL url, ChannelHandler listener) throws RemotingException { return new NettyServer(url, listener); } // ...... }