用場景
當(dāng)我們的服務(wù)收到一個(gè)請求后,需要大量調(diào)用下游服務(wù)獲取業(yè)務(wù)數(shù)據(jù)凡傅,然后對數(shù)據(jù)進(jìn)行轉(zhuǎn)換辟狈、計(jì)算后,響應(yīng)給請求方。
如果我們采用串行獲取下游數(shù)據(jù)哼转,勢必會增加響應(yīng)時(shí)長明未,降低接口的qps。如果是并行獲取下游數(shù)據(jù)壹蔓,則是不錯的趟妥。
最直接想到的并行獲取方法,無非是將一個(gè)個(gè)獲取數(shù)據(jù)的方法封裝成一個(gè)個(gè)task佣蓉,然后放到線程池里執(zhí)行披摄。但這種沒經(jīng)過設(shè)計(jì)的使用方式,易用性很低勇凭,可復(fù)用性也很低疚膊。
經(jīng)本人在實(shí)際的業(yè)務(wù)系統(tǒng)中,多次思考與設(shè)計(jì)虾标。終于設(shè)計(jì)出當(dāng)前這個(gè)框架寓盗。
特點(diǎn):絕對的簡單、絕對的易用夺巩。
相關(guān)概念
- BizData
業(yè)務(wù)數(shù)據(jù)對象贞让。用于將下游獲取到的數(shù)據(jù)封裝到此對象中。
開發(fā)者需自定義此對象柳譬,并實(shí)現(xiàn)IBizData接口
- BizDataProvider
業(yè)務(wù)數(shù)據(jù)對象提供者喳张。此對象類似于分層結(jié)構(gòu)中的Service層,其調(diào)用下游數(shù)據(jù)源(可以是rpc調(diào)用等)將得到的數(shù)據(jù)封裝到BizData對象中美澳。
此類需要添加@BizDataProvider注解销部。其方法返回值一定要是BizData對象
使用
在spring的xml中配置:
<!-- 初始化框架,并設(shè)置用于并行獲取業(yè)務(wù)數(shù)據(jù)的線程池配置 -->
<bean class="com.dyz.pget.core.BizDataManager" init-method="init" destroy-method="destroy">
<property name="corePoolSize" value="12"/>
<property name="maximumPoolSize" value="200"/>
<property name="keepAliveTime" value="0"/>
<property name="queueSize" value="1000"/>
</bean>
第一步:自定義BizData對象
public class UserInfoBizData implements IBizData{
private Long userId;
private String name;
private Integer age;
/**
* 必須提供默認(rèn)構(gòu)造參數(shù)
*/
public UserInfoBizData() {
}
public UserInfoBizData(Long userId, String name, Integer age) {
this.userId = userId;
this.name = name;
this.age = age;
}
/**
* 如果此數(shù)據(jù)對象獲取失敗時(shí)的默認(rèn)兜底值制跟。如果不支持兜底舅桩,則返回null即可。
* @return
*/
@Override
public IBizData defaultBizData() {
return null;
}
@Override
public String format2String() {
return new StringBuilder()
.append("ID:").append(userId)
.append(",名字:").append(name)
.append(",年齡:").append(age)
.toString();
}
}
//篇幅問題雨膨,此處只貼了一個(gè)BizData的代碼
第二步:編寫對應(yīng)的BizDataProvider
@BizDataProvider
public class TestBizDataProvider {
/**
* 異常要拋出擂涛,框架會捕獲
* @param userId
* @return
* @throws Exception
*/
public UserInfoBizData getUserInfoBizData(long userId)throws Exception{
//調(diào)用遠(yuǎn)程rpc或者其他數(shù)據(jù)源得到數(shù)據(jù),并封裝到UserInfoBizData對象中
return new UserInfoBizData(userId,"張三",20);
}
public ProductInfoBizData getProductInfoBizData(long shopId,long productId)throws Exception{
//調(diào)用遠(yuǎn)程rpc或者其他數(shù)據(jù)源得到數(shù)據(jù)聊记,并封裝到ProductInfoBizData對象中
return new ProductInfoBizData(productId,shopId,"啤酒");
}
}
第三步:獲取數(shù)據(jù)
①Getter模式:
使用案例代碼:
@Test
public void testGetter() throws BizDataFetchException {
long userId = 1345L;
long shopId = 11L;
long productId = 11011L;
//并行獲取用戶信息撒妈、商品信息、門店信息三個(gè)數(shù)據(jù)排监。超時(shí)時(shí)間是100毫秒
List<IBizData> bizDataList = BizDataGetter.build()
.get(UserInfoBizData.class,userId)
.get(ProductInfoBizData.class,shopId,productId)
.get(ShopInfoBizData.class,shopId)
.doGet(100L);
UserInfoBizData userInfoBizData = (UserInfoBizData)bizDataList.get(0);
ProductInfoBizData productInfoBizData = (ProductInfoBizData)bizDataList.get(1);
ShopInfoBizData shopInfoBizData = (ShopInfoBizData)bizDataList.get(2);
System.out.println(userInfoBizData.format2String());
System.out.println(productInfoBizData.format2String());
System.out.println(shopInfoBizData.format2String());
}
Injector模式:
定義一個(gè)數(shù)據(jù)包裹對象狰右,存放所需要的數(shù)據(jù)對象
public class BizDataWrapper {
private UserInfoBizData userInfoBizData;
private ShopInfoBizData shopInfoBizData;
private ProductInfoBizData productInfoBizData;
public UserInfoBizData getUserInfoBizData() {
return userInfoBizData;
}
public ShopInfoBizData getShopInfoBizData() {
return shopInfoBizData;
}
public ProductInfoBizData getProductInfoBizData() {
return productInfoBizData;
}
}
使用案例代碼:
@Test
public void testGetter() throws BizDataFetchException {
long userId = 1345L;
long shopId = 11L;
long productId = 11011L;
BizDataWrapper bizDataWrapper = new BizDataWrapper();
//并行獲取用戶信息、商品信息舆床、門店信息三個(gè)數(shù)據(jù)棋蚌。并注入到bizDataWrapper中嫁佳,以方便使用。超時(shí)時(shí)間是100毫秒
BizDataInjector.build(bizDataWrapper)
.inject(UserInfoBizData.class,userId)
.inject(ProductInfoBizData.class,shopId,productId)
.inject(ShopInfoBizData.class,shopId)
.doInject(100L);
System.out.println(bizDataWrapper.getUserInfoBizData().format2String());
System.out.println(bizDataWrapper.getProductInfoBizData().format2String());
System.out.println(bizDataWrapper.getShopInfoBizData().format2String());
}
結(jié)尾
相信你使用后谷暮,一定會覺著簡單實(shí)用蒿往。
不多說了,貼上github地址:https://github.com/yongzhidai/pget
注:使用時(shí)坷备,沒必要把源代碼粘到業(yè)務(wù)系統(tǒng)中熄浓,自己打個(gè)jar包情臭,讓業(yè)務(wù)系統(tǒng)依賴下就OK了省撑。