各協議暴露和引用服務的邏輯
1、各協議暴露服務邏輯
1.1 Duboo協議
1)初始化DubboExporter對象,初始化參數包括invoker對象,key,以及AbstractProtocol.exporterMap引用,並存入AbstractProtocol.exporterMap中;消費端發起的遠程調用通過底層消息通道的傳輸到服務端之後,此類中根據服務端URL生成的key在AbstractProtocol.exporterMap中查找到相應的Exporter對象,通過此Exporter對象找到Invoker對象,調用Invoker.invoke()方法,繼續向上傳遞至服務端的業務層,進行業務邏輯的調用。
2)開啓服務,如下代碼所示,對於相同的服務提供者IP和端口號,只開啓一個服務監聽通道,該通道封裝在ExchangeServer對象中。若相同的服務提供者再次開啓服務,則只調用ExchangeServer對象的reset方法進行服務通道的重新設置,例如監聽線程池大小、心跳頻率等參數的重新設置。
3)創建ExchangeServer對象。具體過程如下:
3.1)檢查<dubbo:protocol>標籤的server屬性配置值是否支持,目前Dubbo協議服務端支持的NIO框架有netty、mina、grizzly三種,缺省爲netty;
3.2)在DubboProtocol類中實例化內部類得到ExchangeHandler對象,該內部類繼承了ExchangeHandlerAdapter 類,並實現了reply、received、connected、disconnected四個方法。
3.3)調用Exchangers.bind(URL url, ExchangeHandlerhandler)方法創建ExchangeServer對象,其中入參url爲服務端提供服務的URL,handler爲內部匿名類DubboProtocol $requestHandler。
3.4)根據URL地址的exchanger參數獲取具體的Exchanger類,目前只支持HeaderExchanger。則調用HeaderExchanger. bind(URL url, ExchangeHandlerhandler)方法,在此方法中創建HeaderExchangeServer對象。具體過程如下:
3.4.1)用HeaderExchangeHandler類封裝上述內部匿名類;該類的主要作用有兩個:第一,對通道的讀寫時間戳進行更新,用於輔助心跳檢測;第二,發起回調客戶端的服務;
3.4.2)用DecodeHandler類對上面的類進行封裝,該類是對信息進行序列化以及反序列化操作,對有回調函數的遠程消費要生成回調函數的代理作爲參數傳遞到上層;
3.4.3)然後調用Transporters.bind(URL url, ChannelHandler...handlers)方法生成Server對象。若入參有多個handlers對象,則使用ChannelHandlerDispatcher類進行封裝;根據<dubbo:protocol>標籤的server屬性配置的NIO框架來選擇調用具體的Transporter類的bind方法,對於mina框架創建MinaServer對象,netty框架創建NettyServer對象,grizzly框架創建GrizzlyServer對象,返回具體的Server對象。在初始化Server對象的過程中,第一,完成服務端口的啓動並監聽消息通道;第二,調用ChannelHandlers.wap(ChannelHander,URL)方法將上面的DecodeHandler對象依次通過AllChannelHandler、HeartbeatHandler、MultiMessageHandler的進行封裝,最後賦值給Server對象的ChannelHandler成員變量。
3.4.4)最後調用HeaderExchangeServer(Server server)方法,用HeaderExchangeServer類封裝上面的Server對象,該類主要是啓一個線程來定時發送鏈路的心跳。
下圖爲各個類的封裝結構圖下圖爲Dubbo協議暴露服務的處理邏輯活動圖
1.2 Rest協議
1、檢查AbstractProtocol.exporterMap中是否存在該URL的Server對象,若沒有則調用RestServerFactory.createServer(String name)方法創建,參數name由URL中的參數server的值指定,目前支持如下參數值。
1)值爲“servlet”、“jetty”、“tomcat”時創建DubboHttpServer對象;
2)值爲“netty”時創建NettyServer對象,內部封裝了NettyJaxrsServer對象;
3)值爲“sunhttp”時創建SunHttpServer對象,內部封裝了SunHttpJaxrsServer對象;
2、如果server 參數的值等於“servlet”則從ServletManager.contextMap中獲取key=-1234 的ServletContext對象;並且必須配置外部servlet對象的上下文路徑與URL的上下文路徑contextpath一致。
ServletManager類維護全局唯一的Map,保存全局的上下文對象,key=-1234的ServletContext對象是在BootstrapListener的contextInitialized 方法中被存入進去的,該類實現了ServletContextListener接口,在外部servlet服務啓動時將該服務的上下文加入到此全局Map中。因此需要在web.xml中配置BootstrapListener。3、在上下文路徑下面發佈Expoter對象;代碼如下:
2各協議引用服務邏輯
2.1 Duboo協議
1、創建ExchangeClient對象。若服務提供者URL地址中有connections參數值(在<dubbo:service >標籤中配置),則每個服務創建指定條數的鏈路(即ExchangeClient對象);若沒有參數則服務消費端與服務提供端直接的所有服務共用一條長鏈接(即ExchangeClient對象)。
1)獲取服務端配置的client參數,若缺省則使用server參數配置,默認選擇netty;
2)設置心跳heartbeat=60000
3)爲了減小長連接數,可以設置是否延遲鏈接,配置<dubbo:protocol>的參數lazy;當lazy=true時,則創建LazyConnectExchangeClient對象,待真正發起遠程調用時,再創建ExchangeClient對象(即與服務端創建連接);否則立刻調用HeaderExchanger.connect方法創建與服務端的鏈接(HeaderExchangeClient對象),具體過程如下:
3.1)在DubboProtocol中創建了內部匿名類DubboProtocol $requestHandler,該類實現了抽象類ExchangeHandlerAdapter。
3.2)用HeaderExchangeHandler類封裝上述內部匿名類;該類的主要作用有兩個:第一,對通道的讀寫時間戳進行更新,用於輔助心跳檢測;第二,發起回調客戶端的服務。
3.3)用DecodeHandler類對上面的類進行封裝,該類是對信息進行序列化以及反序列化操作,對有回調函數的遠程消費要生成回調函數的代理作爲參數傳遞到上層;
3.4)調用Transporters. connect (URL url,ChannelHandler... handlers)方法創建Client對象。若入參有多個handlers對象,則使用ChannelHandlerDispatcher類進行封裝;根據<dubbo:protocol>標籤的client屬性配置的NIO框架來選擇調用具體的Transporter類的connect方法,對於mina框架創建MinaClient對象,netty框架創建NettyClient對象,grizzly框架創建GrizzlyClient對象,返回具體的Client對象。在初始化Client對象的過程中,第一,完成與服務端的建鏈;第二調用ChannelHandlers.wap(ChannelHander,URL)方法將上面的DecodeHandler對象依次通過AllChannelHandler、HeartbeatHandler、MultiMessageHandler的進行封裝,最後賦值給Client對象的ChannelHandler成員變量。
3.5)最後調用將上述client對象通過HeaderExchangeClient構造函數封裝成HeaderExchangeClient對象並返回。
4)用ReferenceCountExchangeClient封裝上面的HeaderExchangeClient對象;
2、初始化DubboInvoker對象,將ExchangeClient對象數組賦值給成員變量clients,將服務引用的Invoker代理賦值給invokers變量,並返回該對象。
下圖是類之間封裝的結構圖
下圖爲Dubbo協議引用服務的活動圖
2.2 Rest協議
1、採用RestEasy技術創建與服務消費端的鏈接;
2、通過代理工廠ProxyFactory$Adpative創建上面鏈接對象的代理對象Invoker;
3、實現內部類並返回該內部類的初始化對象,該內部類繼承AbstractInvoker類,並重現了doInvoke方法,在該方法中調用上面Invoker對象的invoke方法。