引入接口jar
將jar包 install到本地maven倉庫
在windows的cmd下運(yùn)行如下指令
mvn install:install-file -DgroupId=com.lczyfz.cscrawler -DartifactId=api -Dversion=1.0-SNAPSHOT -Dpackaging=jar -Dfile=E:\ cscrawler.jar
然后在pom文件中引入
<!-- 服務(wù)化API依賴 -->
<dependency>
<groupId>com.lczyfz.cscrawler</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
或者將jar放到工程lib中
<dependency>
<groupId>bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.13</version>
<systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/UserAgentUtils-1.13.jar</systemPath>
</dependency>
調(diào)用說明
在調(diào)用的類引入
import com.alibaba.dubbo.config.annotation.Reference;
使用注解注入對象
@Reference
TestCrawlerApi testCrawlerApi;
//調(diào)用對象的方法
System.out.println("===Service====" + testCrawlerApi.sayCrawler("Service"));
發(fā)布說明
創(chuàng)建api
package com.lczyfz.cscrawler.api;
/**
* Created by maple on 2019-01-23.
*/
public interface TestCrawlerApi {
public String sayCrawler(String name);
}
實(shí)現(xiàn)接口换况,在類引入
import com.alibaba.dubbo.config.annotation.Reference;
import com.lczyfz.cscrawler.api.TestCrawlerApi;
使用@Service
package com.lczyfz.cscrawler.modules.test.service;
import com.alibaba.dubbo.config.annotation.Reference;
import com.lczyfz.cscrawler.api.TestCrawlerApi;
import com.lczyfz.csstorage.api.TestApi;
import org.springframework.stereotype.Service;
/**
* Created by maple on 2019-01-23.
*/
@org.springframework.stereotype.ServiceService
@com.alibaba.dubbo.config.annotation.Service
public class TryApiService implements TestCrawlerApi{
@Override
public String sayCrawler(String name) {
return "Crawler " + name;
}
}
常用配置說明
*啟動時(shí)檢查
@Reference(check = false)
Dubbo 缺省會在啟動時(shí)檢查依賴的服務(wù)是否可用啼辣,不可用時(shí)會拋出異常骤肛,阻止 Spring 初始化完成,以便上線時(shí)贴捡,能及早發(fā)現(xiàn)問題,默認(rèn) check="true"挪丢。
可以通過 check="false" 關(guān)閉檢查捐迫,比如,測試時(shí)籽腕,有些服務(wù)不關(guān)心嗡呼,或者出現(xiàn)了循環(huán)依賴,必須有一方先啟動皇耗。
另外南窗,如果你的 Spring 容器是懶加載的,或者通過 API 編程延遲引用服務(wù)郎楼,請關(guān)閉 check万伤,否則服務(wù)臨時(shí)不可用時(shí),會拋出異常呜袁,拿到 null 引用敌买,如果 check="false",總是會返回引用阶界,當(dāng)服務(wù)恢復(fù)時(shí)放妈,能自動連上北救。
*多版本
當(dāng)一個(gè)接口實(shí)現(xiàn),出現(xiàn)不兼容升級時(shí)芜抒,可以用版本號過渡珍策,版本號不同的服務(wù)相互間不引用。
可以按照以下的步驟進(jìn)行版本遷移:
在低壓力時(shí)間段宅倒,先升級一半提供者為新版本
再將所有消費(fèi)者升級為新版本
然后將剩下的一半提供者升級為新版本
老版本服務(wù)提供者配置:
@com.alibaba.dubbo.config.annotation.Service(version = "1.0.0")
新版本服務(wù)提供者配置:
@com.alibaba.dubbo.config.annotation.Service(version = "2.0.0")
老版本服務(wù)消費(fèi)者配置:
@Reference(version = "1.0.0")
新版本服務(wù)消費(fèi)者配置:
@Reference(version = "2.0.0")
*回聲測試
回聲測試用于檢測服務(wù)是否可用攘宙,回聲測試按照正常請求流程執(zhí)行,能夠測試整個(gè)調(diào)用是否通暢拐迁,可用于監(jiān)控蹭劈。
所有服務(wù)自動實(shí)現(xiàn) EchoService 接口,只需將任意服務(wù)引用強(qiáng)制轉(zhuǎn)型為 EchoService线召,即可使用铺韧。
// 遠(yuǎn)程服務(wù)引用
EchoService echoService = (EchoService) memberService; // 強(qiáng)制轉(zhuǎn)型為EchoService
// 回聲測試可用性
String status = echoService.$echo("OK");
assert(status.equals("OK"));
上下文信息
上下文中存放的是當(dāng)前調(diào)用過程中所需的環(huán)境信息。所有配置信息都將轉(zhuǎn)換為 URL 的參數(shù)缓淹,參見 schema 配置參考手冊 中的對應(yīng)URL參數(shù)一列哈打。
RpcContext 是一個(gè) ThreadLocal 的臨時(shí)狀態(tài)記錄器,當(dāng)接收到 RPC 請求讯壶,或發(fā)起 RPC 請求時(shí)料仗,RpcContext 的狀態(tài)都會變化。比如:A 調(diào) B伏蚊,B 再調(diào) C立轧,則 B 機(jī)器上,在 B 調(diào) C 之前躏吊,RpcContext 記錄的是 A 調(diào) B 的信息氛改,在 B 調(diào) C 之后,RpcContext 記錄的是 B 調(diào) C 的信息比伏。
- 服務(wù)消費(fèi)方
// 遠(yuǎn)程調(diào)用
xxxService.xxx();
// 本端是否為消費(fèi)端胜卤,這里會返回true
boolean isConsumerSide = RpcContext.getContext().isConsumerSide();
// 獲取最后一次調(diào)用的提供方IP地址
String serverIP = RpcContext.getContext().getRemoteHost();
// 獲取當(dāng)前服務(wù)配置信息,所有配置信息都將轉(zhuǎn)換為URL的參數(shù)
String application = RpcContext.getContext().getUrl().getParameter("application");
// 注意:每發(fā)起RPC調(diào)用凳怨,上下文狀態(tài)會變化
yyyService.yyy();
- 服務(wù)提供方
public class XxxServiceImpl implements XxxService {
public void xxx() {
// 本端是否為提供端瑰艘,這里會返回true
boolean isProviderSide = RpcContext.getContext().isProviderSide();
// 獲取調(diào)用方IP地址
String clientIP = RpcContext.getContext().getRemoteHost();
// 獲取當(dāng)前服務(wù)配置信息,所有配置信息都將轉(zhuǎn)換為URL的參數(shù)
String application = RpcContext.getContext().getUrl().getParameter("application");
// 注意:每發(fā)起RPC調(diào)用肤舞,上下文狀態(tài)會變化
yyyService.yyy();
// 此時(shí)本端變成消費(fèi)端紫新,這里會返回false
boolean isProviderSide = RpcContext.getContext().isProviderSide();
}
}
訪問日志
如果你想記錄每一次請求信息,可開啟訪問日志李剖,類似于apache的訪問日志芒率。注意:此日志量比較大,請注意磁盤容量篙顺。
將訪問日志輸出到當(dāng)前應(yīng)用的log4j日志:
<dubbo:protocol accesslog="true" />
*性能調(diào)優(yōu)參數(shù)
- delay 默認(rèn)0 延遲注冊服務(wù)時(shí)間(毫秒) 偶芍,設(shè)為-1時(shí)充择,表示延遲到Spring容器初始化完成時(shí)暴露服務(wù)
- timeout 默認(rèn)1000 遠(yuǎn)程服務(wù)調(diào)用超時(shí)時(shí)間(毫秒)
- retries 默認(rèn) 2 遠(yuǎn)程服務(wù)調(diào)用重試次數(shù),不包括第一次調(diào)用匪蟀,不需要重試請?jiān)O(shè)為0
本地存根
遠(yuǎn)程服務(wù)后椎麦,客戶端通常只剩下接口,而實(shí)現(xiàn)全在服務(wù)器端材彪,但提供方有些時(shí)候想在客戶端也執(zhí)行部分邏輯观挎,比如:做 ThreadLocal 緩存,提前驗(yàn)證參數(shù)段化,調(diào)用失敗后偽造容錯(cuò)數(shù)據(jù)等等嘁捷,此時(shí)就需要在 API 中帶上 Stub,客戶端生成 Proxy 實(shí)例显熏,會把 Proxy 通過構(gòu)造函數(shù)傳給 Stub雄嚣,然后把 Stub 暴露給用戶,Stub 可以決定要不要去調(diào) Proxy喘蟆。
在 spring 配置文件中按以下方式配置:
@com.alibaba.dubbo.config.annotation.Service(stub = "com.foo.BarServiceStub")
提供 Stub 的實(shí)現(xiàn) :
package com.foo;
public class BarServiceStub implements BarService {
private final BarService barService;
// 構(gòu)造函數(shù)傳入真正的遠(yuǎn)程代理對象
public (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ù)";
}
}
}
*本地偽裝
本地偽裝 通常用于服務(wù)降級仔沿,比如某驗(yàn)權(quán)服務(wù)坐桩,當(dāng)服務(wù)提供方全部掛掉后尺棋,客戶端不拋出異常,而是通過 Mock 數(shù)據(jù)返回授權(quán)失敗绵跷。
在 spring 配置文件中按以下方式配置:
@Reference(mock = "com.foo.BarServiceMock")
在工程中提供 Mock 實(shí)現(xiàn) :
package com.foo;
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)方經(jīng)常需要 try-catch 捕獲異常,如:
Offer offer = null;
try {
offer = offerService.findOffer(offerId);
} catch (RpcException e) {
logger.error(e);
}
請考慮改為 Mock 實(shí)現(xiàn)碾局,并在 Mock 實(shí)現(xiàn)中 return null荆残。如果只是想簡單的忽略異常,在 2.0.11
以上版本可用:
<dubbo:reference interface="com.foo.BarService" mock="return null" />