使用SpringCloudAlibaba整合Dubbo
SpringCloudAlibaba整合Dubbo
Spring Cloud是一套較為完整的架構(gòu)方案,而Dubbo只是服務(wù)治理與RPC實(shí)現(xiàn)方案。
Dubbo的注冊(cè)中心采用了ZooKeeper,而Spring Cloud體系中的注冊(cè)中心并不支持ZooKeeper。直到Spring Cloud Alibaba的出現(xiàn),才得以解決這樣的問(wèn)題,Spring Cloud Alibaba中的Nacos來(lái)作為服務(wù)注冊(cè)中心,并且在此之下可以如傳統(tǒng)的Spring Cloud應(yīng)用一樣地使用Ribbon或Feign來(lái)實(shí)現(xiàn)服務(wù)消費(fèi),并提供了Spring Cloud Alibaba下額外支持的RPC方案:Dubbo
構(gòu)建服務(wù)接口
public interface HelloService { String hello(String name); }
構(gòu)建服務(wù)接口提供方
(1)創(chuàng)建一個(gè)Spring Boot項(xiàng)目,在pom.xml中引入第一步中構(gòu)建的API包以及Spring Cloud Alibaba對(duì)Nacos和Dubbo的依賴
<dependency> <groupId>top.onething</groupId> <artifactId>product-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.2.1.RELEASE</version> </dependency> <!--Dubbo Spring Cloud基于Spring Cloud Commons開(kāi)發(fā)的,org.apache.http.client.HttpClient類確實(shí)存在于舊版本的httpclient中, 但是它使用內(nèi)部的org.apache.http.impl.client.HttpClientBuilder類在新版本中卻不存在--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.4</version> <scope>compile</scope> </dependency>
spring-cloud-starter-dubbo基于spring-cloud-starter-commons開(kāi)發(fā)的,org.apache.http.client.HttpClient類確實(shí)存在于舊版本的httpclient中,但是它使用內(nèi)部的org.apache.http.impl.client.HttpClientBuilder類在新版本中卻不存在。如果類路徑上沒(méi)有HttpClient,則HttpClientConfiguration自動(dòng)配置將失敗 HttpClientConfiguration的自動(dòng)配置因?qū)ttpClient的舊依賴性而失敗,異常如下所示:
java.lang.IllegalStateException: Error processing condition on org.springframework.cloud.commons.httpclient.HttpClientConfiguration$ApacheHttpClientConfiguration.apacheHttpClientBuilder
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClientBuilder
(2)實(shí)現(xiàn)Dubbo接口
@Service public class HelloServiceImpl implements HelloService { @Override public String hello(String name) { return "hello " + name; } }
注意:@Service注解不是Spring的,而是dubbo的,完全限定名為:org.apache.dubbo.config.annotation.Service
(3)配置Dubbo服務(wù)相關(guān)的信息
配置說(shuō)明如下:
spring: application: name: dubbo-consumer cloud: nacos: discovery: server-addr: www.onething.top:8848 # nacos服務(wù)注冊(cè)中心的地址 cluster-name: consumer-cluster #集群名稱 namespace: b7ef9579-df75-41c2-8a95-e04aa03c273a #命名空間 config: server-addr: www.onething.top:8848 # nacos配置中心地址 namespace: b7ef9579-df75-41c2-8a95-e04aa03c273a file-extension: yaml #配置文件的后綴名 refresh-enabled: true #默認(rèn)true:自動(dòng)刷新 dubbo: protocol: #Dubbo 服務(wù)暴露的協(xié)議配置,其中子屬性 name 為協(xié)議名稱,port 為協(xié)議端口( -1 表示自增端口,從 20880 開(kāi)始) name: dubbo port: -1 #dubbo協(xié)議缺省端口為20880,rmi協(xié)議缺省端口為1099,http和hessian協(xié)議缺省端口為80;如果沒(méi)有配置port,則自動(dòng)采用默認(rèn)端口,如果配置為-1,則會(huì)分配一個(gè)沒(méi)有被占用的端口。Dubbo 2.4.0+,分配的端口在協(xié)議缺省端口的基礎(chǔ)上增長(zhǎng),確保端口段可控 registry: #dubbo服務(wù)注冊(cè)端口,注冊(cè)中心服務(wù)器地址,如果地址沒(méi)有端口缺省為9090,同一集群內(nèi)的多個(gè)地址用逗號(hào)分隔,如:ip:port,ip:port #其中前綴spring-cloud說(shuō)明:掛載到 Spring Cloud注冊(cè)中心 address: spring-cloud://www.onething.top:8848 #check: false #關(guān)閉注冊(cè)中心是否啟動(dòng)的相關(guān)檢查,false表示不檢查注冊(cè)中心是否啟動(dòng),就不會(huì)報(bào)錯(cuò) cloud: subscribed-services: dubbo-product consumer: check: false #關(guān)閉訂閱服務(wù)是否啟動(dòng)的檢查【檢查時(shí),沒(méi)有服務(wù)提供者會(huì)報(bào)錯(cuò)】
- dubbo.scan.base-packages: 指定 Dubbo 服務(wù)實(shí)現(xiàn)類的掃描基準(zhǔn)包
- dubbo.protocol: Dubbo 服務(wù)暴露的協(xié)議配置,其中子屬性 name 為協(xié)議名稱,port 為協(xié)議端口( -1 表示自增端口,從 20880 開(kāi)始)
- dubbo.registry: Dubbo 服務(wù)注冊(cè)中心配置,其中子屬性 address 的值 “spring-cloud://localhost”,說(shuō)明掛載到 Spring Cloud 注冊(cè)中心
注意:如果使用Spring Boot 2.1及更高版本時(shí)候,需要增加配置spring.main.allow-bean-definition-overriding=true
(4)創(chuàng)建應(yīng)用主類
@EnableDiscoveryClient【此注解可以省略】 @SpringBootApplication public class DubboServerApplication { public static void main(String[] args) { SpringApplication.run(DubboServerApplication.class, args); } }
構(gòu)建服務(wù)接口消費(fèi)方法
(1)創(chuàng)建一個(gè)Spring Boot項(xiàng)目,在pom.xml中引入第一步中構(gòu)建的API包以及Spring Cloud Alibaba對(duì)Nacos和Dubbo的依賴,具體內(nèi)容與服務(wù)提供方一致
<dependencies> <dependency> <groupId>top.onething</groupId> <artifactId>product-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.1.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-dubbo</artifactId> <version>2.2.1.RELEASE</version> </dependency> </dependencies>
(2)配置Dubbo服務(wù)相關(guān)的信息
spring: application: name: dubbo-consumer cloud: nacos: discovery: server-addr: www.onething.top:8848 # nacos服務(wù)注冊(cè)中心的地址 cluster-name: consumer-cluster #集群名稱 namespace: b7ef9579-df75-41c2-8a95-e04aa03c273a #命名空間 config: server-addr: www.onething.top:8848 # nacos配置中心地址 namespace: b7ef9579-df75-41c2-8a95-e04aa03c273a group: test-group file-extension: yaml #配置文件的后綴名 dubbo: protocol: #Dubbo 服務(wù)暴露的協(xié)議配置,其中子屬性 name 為協(xié)議名稱,port 為協(xié)議端口( -1 表示自增端口,從 20880 開(kāi)始) name: dubbo port: -1 #dubbo協(xié)議缺省端口為20880,rmi協(xié)議缺省端口為1099,http和hessian協(xié)議缺省端口為80;如果沒(méi)有配置port,則自動(dòng)采用默認(rèn)端口,如果配置為-1,則會(huì)分配一個(gè)沒(méi)有被占用的端口。Dubbo 2.4.0+,分配的端口在協(xié)議缺省端口的基礎(chǔ)上增長(zhǎng),確保端口段可控 registry: #其中前綴spring-cloud說(shuō)明:掛載到 Spring Cloud注冊(cè)中心 address: spring-cloud://www.onething.top:8848 #dubbo服務(wù)注冊(cè)端口,注冊(cè)中心服務(wù)器地址,如果地址沒(méi)有端口缺省為9090,同一集群內(nèi)的多個(gè)地址用逗號(hào)分隔,如:ip:port,ip:port cloud: subscribed-services: dubbo-product
(3)創(chuàng)建應(yīng)用主類,并實(shí)現(xiàn)一個(gè)接口,在這個(gè)接口中調(diào)用Dubbo服務(wù)
@EnableDiscoveryClient @SpringBootApplication @RestController public class DubboClientApplication { @Reference HelloService helloService; public static void main(String[] args) { SpringApplication.run(DubboClientApplication.class, args); } @GetMapping("/test") public String test() { return helloService.hello("didispace.com"); } }
注意:這里的@Reference注解是org.apache.dubbo.config.annotation.Reference
SpringCloudAlibaba之Dubbo總結(jié)
GitHub地址:https://github.com/apache/dubbo
Dubbo的故事比較長(zhǎng)了,Demo中也有調(diào)用的示例,所以示例就不補(bǔ)充了,我的gitee倉(cāng)庫(kù)上也有一些可參考的示例。目前在這里就只針對(duì)目前的最新版本2.7.7,做一點(diǎn)總結(jié)把。
另外,關(guān)于Dubbo,出來(lái)這么多年了,很多人更關(guān)注Dubbo的動(dòng)態(tài)代理、底層Netty協(xié)議等一些問(wèn)題。但是我覺(jué)得,其實(shí)更應(yīng)該關(guān)注的是Dubbo在服務(wù)調(diào)用這個(gè)場(chǎng)景中做到了哪些,想到了哪些,這些應(yīng)該是比手寫(xiě)Dubbo更有價(jià)值的地方。這中間的關(guān)系就像架構(gòu)師跟程序員之間的差距,并不是架構(gòu)師代碼就寫(xiě)得就比程序員好,而是架構(gòu)師能考慮到各種情況,組合成系統(tǒng)化解決實(shí)際問(wèn)題的解決方案。
Dubbo概述
官網(wǎng)的特性描述:
- 面向接口代理的高性能RPC調(diào)用:提供高性能的基于代理的遠(yuǎn)程調(diào)用能力,服務(wù)以接口為粒度,為開(kāi)發(fā)者屏蔽遠(yuǎn)程調(diào)用底層細(xì)節(jié)。
- 智能負(fù)載均衡:內(nèi)置多種負(fù)載均衡策略,智能感知下游節(jié)點(diǎn)健康狀況,顯著減少調(diào)用延遲,提高系統(tǒng)吞吐量。
- 服務(wù)自動(dòng)注冊(cè)與發(fā)現(xiàn):支持多種注冊(cè)中心服務(wù),服務(wù)實(shí)例上下線實(shí)時(shí)感知。
- 高度可擴(kuò)展能力:遵循微內(nèi)核+插件的設(shè)計(jì)原則,所有核心能力如Protocol,Transport,Serialization被設(shè)計(jì)為擴(kuò)展點(diǎn),平等對(duì)待內(nèi)置實(shí)現(xiàn)和第三方實(shí)現(xiàn)。
- 運(yùn)行期流量調(diào)度:內(nèi)置條件、腳本等路由策略,通過(guò)配置不同的路由規(guī)則,輕松實(shí)現(xiàn)灰度發(fā)布、同機(jī)房?jī)?yōu)先等功能。
- 可視化的服務(wù)治理與運(yùn)維:提供豐富服務(wù)治理、運(yùn)維工具,隨時(shí)查詢服務(wù)元數(shù)據(jù),服務(wù)健康狀態(tài)即調(diào)用統(tǒng)計(jì)、實(shí)時(shí)下發(fā)路由策略、調(diào)整配置參數(shù)。
這個(gè)圖可以看到Dubbo的各角色職責(zé),Registery負(fù)責(zé)服務(wù)發(fā)現(xiàn)與注冊(cè),Provider往Registry上注冊(cè)服務(wù)信息,Consumer訂閱Registry上的服務(wù)信息,Registry會(huì)及時(shí)向Consumer進(jìn)行推送。然后Consumer從服務(wù)列表中選擇一個(gè)Provider,進(jìn)行服務(wù)調(diào)用。
Dubbo配置方式
Dubbo的服務(wù)有三種配置方式,API方式、基于Spring的XML方式和基于SpringBoot的Properties方式。三種方式的服務(wù)配置在Demo工程中都有實(shí)現(xiàn),就不多說(shuō)了。這里要記錄一下的,是各種配置的優(yōu)先級(jí)。
三種配置方式之間的關(guān)系
顯而易見(jiàn),API方式其實(shí)已經(jīng)不是服務(wù)化的配置方式了,是底層的實(shí)現(xiàn)方式,展示的是如何將Dubbo的幾個(gè)核心對(duì)象組裝成服務(wù)。正常情況下也是不太會(huì)用得到的,只是在一些脫離Spring的環(huán)境中可以偶爾強(qiáng)行用一下,比如MapReduce、spark計(jì)算等一些情況可以強(qiáng)行用上一點(diǎn)。
而后兩種配置方式,其實(shí)效果是等價(jià)的。例如 dubbo.application.name=foo和<dubbo:registry name=“foo” />是等價(jià)的,而dubbo.registry.address=nacos://localhost:8848和<dubbo:registry address="nacos://localhost:8848"這兩個(gè)也是等價(jià)的。而在多配置的時(shí)候,需要用ID進(jìn)行區(qū)分時(shí),dubbo.protocol.rmi.port=1099 equals to <dubbo:protocol id=“rmi” name=“rmi” port=“1099” />這兩種方式也是等價(jià)的。而且實(shí)際上,在SpringBoot工程中,也是可以通過(guò)引入@ImportResource注解,來(lái)指定dubbo的服務(wù)配置XML的。
而如果在一個(gè)SpringBoot工程中,將兩種配置方式整合在一起,那配置的優(yōu)先級(jí)又是怎樣的呢?這時(shí)的優(yōu)先級(jí)是{java -D}>{xml}>{properties}。并且,如果一個(gè)項(xiàng)目中有多個(gè)dubbo.properties(例如多個(gè)jar包中都有配置文件),那么,dubbo會(huì)隨機(jī)的讀取一個(gè)配置文件,同時(shí)會(huì)拋出異常信息。官方的建議也是多使用xml方式進(jìn)行配置。
另外,基于SpringCloud的properties配置,其實(shí)還有另一種基于注解的服務(wù)聲明方式,@Service暴露服務(wù),@Reference調(diào)用服務(wù),而這種方式,其實(shí)跟xml配置的方式也是等價(jià)的。
服務(wù)端與消費(fèi)端的配置優(yōu)先級(jí)
有很多服務(wù)屬性如retris(重試次數(shù))、timeout(超時(shí)時(shí)間)、loadbalance(負(fù)載方法)等屬性,在服務(wù)提供端和服務(wù)消費(fèi)端都可以進(jìn)行配置。此時(shí),服務(wù)消費(fèi)端的配置是優(yōu)先于服務(wù)提供端的。服務(wù)提供端的配置相當(dāng)于是服務(wù)的默認(rèn)屬性,因此,官方建議要在服務(wù)提供端盡量多的配置這些服務(wù)屬性。另外,官方還建議,在服務(wù)端盡量提供更詳細(xì)的服務(wù)配置,例如在配置服務(wù)時(shí),如果可以的話,對(duì)每個(gè)method提供詳細(xì)的配置。例如:
<dubbo:protocol threads="200" /> <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" executes="200" > <dubbo:method name="findAllPerson" executes="50" /> </dubbo:service>
這樣指定了線程池200,而findAllPerson的線程池為50.
指定dubbo的Cache File
官方建議要在registry中指定file。例如<dubbo:registry file=”${user.home}/output/dubbo.cache” />。這個(gè)Cache File可以緩存服務(wù)注冊(cè)信息,這樣,在注冊(cè)中心停止服務(wù)后,消費(fèi)端依然可以進(jìn)行服務(wù)調(diào)用。由于這個(gè)文件很重要,雖然不指定也會(huì)默認(rèn)生成到本地,但是官方建議是要單獨(dú)指定緩存文件,并且注意不要有多個(gè)工程指定同一個(gè)緩存文件的情況,這樣會(huì)造成文件寫(xiě)入權(quán)限競(jìng)爭(zhēng)以及服務(wù)注冊(cè)信息被覆蓋的情況。
這個(gè)CacheFile機(jī)制可以允許消費(fèi)者繞過(guò)注冊(cè)中心訪問(wèn)服務(wù)提供者,而如果需要防止這種情況,可以使用dubbo的令牌驗(yàn)證機(jī)制,這樣需要在注冊(cè)中心進(jìn)行權(quán)限驗(yàn)證才可以訪問(wèn)。開(kāi)啟方式也很簡(jiǎn)單,在provider或者service指定token屬性即可:
<!--隨機(jī)token令牌,使用UUID生成--> <dubbo:provider interface="com.foo.BarService" token="true" /> <!--固定token令牌,相當(dāng)于密碼--> <dubbo:provider interface="com.foo.BarService" token="123456" />
其他一些有意思的地方
官方的文檔中很詳細(xì)的說(shuō)明了dubbo的許多特性,這里挑一些有意思的特性。其他可以多參考官方文檔。
服務(wù)集群容錯(cuò)機(jī)制
可以在service中指定集群容錯(cuò)機(jī)制,例如 <dubbo:service cluster=“failsafe” />
- 默認(rèn)是Failover,這種模式當(dāng)訪問(wèn)出錯(cuò)時(shí)(超時(shí)等),會(huì)自動(dòng)尋找另外的提供者,發(fā)起重試??梢酝ㄟ^(guò)指定retries來(lái)指定重試次數(shù)–retries配置的次數(shù)不包含第一次請(qǐng)求。這通常用于讀操作,對(duì)于寫(xiě)操作,容易造成服務(wù)冪等問(wèn)題。
- Failfast:只發(fā)起一次服務(wù)調(diào)用,如果出錯(cuò)就立即報(bào)錯(cuò)。這種比較適用于寫(xiě)操作。
- Failsafe:如果服務(wù)調(diào)用出錯(cuò)或者出現(xiàn)異常,則直接忽略。這種比較適用于寫(xiě)日志這類允許失敗的操作。
- Failback:故障自動(dòng)恢復(fù),后臺(tái)記錄失敗的請(qǐng)求,并定期重傳。這種比較適用于消息驅(qū)動(dòng)的場(chǎng)景。
- Forking: 同時(shí)向多個(gè)服務(wù)端發(fā)起請(qǐng)求,一旦有一個(gè)服務(wù)提供端返回成功,則服務(wù)調(diào)用成功。這種比較適用于實(shí)時(shí)性要求較高的讀操作。但是顯然,這樣會(huì)浪費(fèi)更多的服務(wù)資源??梢允褂胒ork屬性配置并行數(shù)。
- BroadCast: 同時(shí)向所有服務(wù)提供端發(fā)起請(qǐng)求,依次請(qǐng)求,并會(huì)報(bào)告每一個(gè)錯(cuò)誤。這通常用于通知所有服務(wù)端進(jìn)行緩存更新之類的操作。
本地服務(wù)存根與本地偽裝 local stub, local mock
1、通常情況下,服務(wù)消費(fèi)端只有一個(gè)接口,對(duì)服務(wù)的調(diào)用實(shí)現(xiàn)全部依賴服務(wù)提供端。但是,有時(shí)候,服務(wù)提供端希望在服務(wù)消費(fèi)端也做一些本地操作,例如做ThreadLocal緩存、參數(shù)檢查、調(diào)用失敗后返回Mock假數(shù)據(jù)等。這樣,有些在SpringCloud中需要在消費(fèi)端用Hystrix做的事情,就可以用這個(gè)本地服務(wù)存根,在服務(wù)端直接幫消費(fèi)端處理完了,這樣可以讓消費(fèi)端更進(jìn)一步忽略服務(wù)調(diào)用細(xì)節(jié)。例如,在服務(wù)提供端做如下配置:
<dubbo:service interface="com.foo.BarService" stub="true" /> or <dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />
然后服務(wù)提供端就可以通過(guò)提供一個(gè)本地存根方法,這樣BarServiceStub的sayHello方法會(huì)在消費(fèi)端的本地執(zhí)行,讓消費(fèi)端在服務(wù)調(diào)用失敗后返回容錯(cuò)數(shù)據(jù)。
public class BarServiceStub implements BarService { private final BarService barService; // 構(gòu)造函數(shù)傳入真正的遠(yuǎn)程代理對(duì)象 public BarServiceStub(BarService barService){ this.barService = barService; } public String sayHello(String name) { // 此代碼在客戶端執(zhí)行, 你可以在客戶端做ThreadLocal本地緩存,或預(yù)先驗(yàn)證參數(shù)是否合法,等等 try { return barService.sayHello(name); } catch (Exception e) { // 你可以容錯(cuò),可以做任何AOP攔截事項(xiàng) return "容錯(cuò)數(shù)據(jù)"; } } }
2、針對(duì)Mock這種容錯(cuò)場(chǎng)景,dubbo可以使用mock屬性進(jìn)行更簡(jiǎn)單的配置;
<dubbo:reference interface="com.foo.BarService" mock="true" /> or <dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
這樣,在barServiceMock中,就不用try cache,而只用關(guān)注cache后的處理。
public class BarServiceMock implements BarService { public String sayHello(String name) { // 你可以偽造容錯(cuò)數(shù)據(jù),此方法只在出現(xiàn)RpcException時(shí)被執(zhí)行 return "容錯(cuò)數(shù)據(jù)"; } }
這樣,服務(wù)消費(fèi)者可以省掉很多不必要的try cache操作。
3、在mock屬性中,可以直接返回一些指定的對(duì)象,從而連實(shí)現(xiàn)代碼都可以省略調(diào)了。例如:
<dubbo:reference interface="com.foo.BarService" mock="return null" />
mock屬性可以返回的對(duì)象有:
- empty:空對(duì)象,代表基本類型的默認(rèn)值,或者空集合等。
- null: java中的null對(duì)象
- boolean: true 或者 false
- JSON 格式: 一個(gè)對(duì)象的JSON反序列化對(duì)象。
還有, mock屬性中,還可以簡(jiǎn)單的拋出異常
<dubbo:reference interface="com.foo.BarService" mock="throw" /> //拋出一個(gè)RPCException異常 <dubbo:reference interface="com.foo.BarService" mock="throw com.foo.MockException" /> //拋出一個(gè)指定異常
4、這個(gè)版本的dubbo中,mock屬性還支持force和fail的mock行為。
fail跟默認(rèn)流程一致,即表示當(dāng)消費(fèi)端遠(yuǎn)程調(diào)用出現(xiàn)異常時(shí)才進(jìn)行。
而force則表示不走遠(yuǎn)程調(diào)用,直接返回mock數(shù)據(jù)。這在調(diào)試時(shí)還是有點(diǎn)用的。
force和fail都支持與上面的return或者throw進(jìn)行組合。、
<dubbo:reference interface="com.foo.BarService" mock="force:return fake" /> or <dubbo:reference interface="com.foo.BarService" mock="force:throw com.foo.MockException" />
5、這個(gè)local mock,在處理服務(wù)調(diào)用異常時(shí),是挺強(qiáng)大的。官方建議,盡量在方法級(jí)別上使用mock,而不要在整個(gè)服務(wù)上使用。像這樣,只在sayHello方法上使用mock.
<dubbo:reference id="demoService" check="false" interface="com.foo.BarService"> <dubbo:parameter key="sayHello.mock" value="force:return fake"/> </dubbo:reference>
6、注意下,stub和mock在服務(wù)的提供端和消費(fèi)端都可以指定,應(yīng)該還是消費(fèi)端的優(yōu)先級(jí)高于提供端。
泛化服務(wù) GenericService
Dubbo的服務(wù)總是面向接口的,意味著服務(wù)調(diào)用總是需要一個(gè)固定的接口對(duì)象,這樣很安全,但是同時(shí)也不夠靈活。而Dubbo可以通過(guò)GenericService泛華服務(wù)來(lái)增加服務(wù)靈活性。
1、服務(wù)提供端:
在服務(wù)提供端,可以用org.apache.dubbo.rpc.service.GenericService替代所有的接口實(shí)現(xiàn)。 例如,先按如下方式提供一個(gè)服務(wù):
<bean id="genericService" class="com.foo.MyGenericService" /> <dubbo:service interface="com.foo.BarService" ref="genericService" />
而指定的MyGenericService,可以通過(guò)繼承GenericService來(lái)實(shí)現(xiàn)擴(kuò)展邏輯:
public class MyGenericService implements GenericService { @Override public Object $invoke(String methodName, String[] parameterTypes, Object[] args) throws GenericException { if ("sayHello".equals(methodName)) { return "Welcome " + args[0]; } } }
這樣就可以在不需要接口的情況下,響應(yīng)服務(wù)端的 barService.sayHello(String args)這樣的服務(wù)請(qǐng)求了。
這種泛化服務(wù)方式同樣支持API方式的服務(wù)暴露,跟xml的配置基本是對(duì)等的。
2、泛化服務(wù)調(diào)用
泛化服務(wù)調(diào)用,只需要在reference中指定generic為true就行。
<dubbo:reference id="barService" interface="com.foo.BarService" generic="true" />
泛化服務(wù)沒(méi)有了預(yù)先定義好的方法,需要使用GenericService的$invoke方法來(lái)進(jìn)行調(diào)用
GenericService barService = (GenericService) applicationContext.getBean("barService"); Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" });
這種調(diào)用方式同樣支持API格式的服務(wù)調(diào)用。
泛化方法的返回對(duì)象,如果是個(gè)POJO的對(duì)象,則會(huì)以Map結(jié)構(gòu)返回POJO的信息,類似于下面的結(jié)構(gòu)
Map<String, Object> map = new HashMap<String, Object>(); // 注意:如果參數(shù)類型是接口,或者List等丟失泛型,可通過(guò)class屬性指定類型。 map.put("class", "com.xxx.PersonImpl"); map.put("name", "xxx"); // Person的屬性 map.put("password", "yyy");
服務(wù)管理控制臺(tái)
Dubbo使用Nacos作為注冊(cè)中心的話,Nacos已經(jīng)可以充當(dāng)服務(wù)控制臺(tái)。
而另外有一個(gè)項(xiàng)目則可替代原有的Dubbo Admin作為Dubbo的服務(wù)管理控制臺(tái)。github地址:https://github.com/apache/dubbo-admin 一個(gè)基于Vue.js和Verify+SpringBoot做的前后端分離的管理控制臺(tái)。
國(guó)人的官網(wǎng)看著舒適,示例豐富,說(shuō)明也很簡(jiǎn)單詳盡,目前版本的Dubbo還有些如分布式事務(wù)之類的功能尚未實(shí)現(xiàn),期待Dubbo更強(qiáng)大把。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SSH框架網(wǎng)上商城項(xiàng)目第17戰(zhàn)之購(gòu)物車基本功能
這篇文章主要為大家詳細(xì)介紹了SSH框架網(wǎng)上商城項(xiàng)目第17戰(zhàn)之購(gòu)物車基本功能的實(shí)現(xiàn)過(guò)程,感興趣的小伙伴們可以參考一下2016-06-06Java利用文件輸入輸出流實(shí)現(xiàn)文件夾內(nèi)所有文件拷貝到另一個(gè)文件夾
這篇文章主要介紹了Java實(shí)現(xiàn)文件夾內(nèi)所有文件拷貝到另一個(gè)文件夾,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03Spring事務(wù)注解@Transactional失效的八種場(chǎng)景分析
最近在開(kāi)發(fā)采用Spring框架的項(xiàng)目中,使用了@Transactional注解,但發(fā)現(xiàn)事務(wù)注解失效了,所以這篇文章主要給大家介紹了關(guān)于Spring事務(wù)注解@Transactional失效的八種場(chǎng)景,需要的朋友可以參考下2021-05-05SpringBoot啟動(dòng)時(shí)如何通過(guò)啟動(dòng)參數(shù)指定logback的位置
這篇文章主要介紹了SpringBoot啟動(dòng)時(shí)如何通過(guò)啟動(dòng)參數(shù)指定logback的位置,在spring boot中,使用logback配置的方式常用的有兩種,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07spring boot security設(shè)置忽略地址不生效的解決
這篇文章主要介紹了spring boot security設(shè)置忽略地址不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07SpringBoot實(shí)現(xiàn)全局異常的封裝和統(tǒng)一處理
在Spring Boot應(yīng)用中,全局異常的處理是一個(gè)非常重要的方面,本文主要為大家詳細(xì)介紹了如何在Spring Boot中進(jìn)行全局異常的封裝和統(tǒng)一處理,需要的可以參考下2023-12-12解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問(wèn)題
這篇文章主要介紹了mybatis使用char類型字段查詢oracle數(shù)據(jù)庫(kù)時(shí)結(jié)果返回null問(wèn)題的解決方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06Java實(shí)現(xiàn)迅雷地址轉(zhuǎn)成普通地址實(shí)例代碼
本篇文章主要介紹了Java實(shí)現(xiàn)迅雷地址轉(zhuǎn)成普通地址實(shí)例代碼,非常具有實(shí)用價(jià)值,有興趣的可以了解一下。2017-03-03完全解析Java編程中finally語(yǔ)句的執(zhí)行原理
這篇文章主要深度介紹了Java編程中finally語(yǔ)句的執(zhí)行原理,細(xì)致講解了finally在異常處理中的流程控制作用,需要的朋友可以參考下2015-11-11