前言
有這麼一個業務場景:部門A服務要使用部門B服務的業務資料,部門A服務使用部門B服務的業務資料前置條件是B部門必須要給A授權。B部門的授權和業務資料分屬為不同服務。其請求流程如下
因為A的鑑權資訊的請求值是固定的,因此鑑權結果大概率也是固定值。當時B部門的業務服務開發同事,為了提高效率。就加了快取,即B的業務服務會將A的鑑權結果快取起來。當時寫法形如下
private final LoadingCache<String,Boolean> checkSvcCache = Caffeine
.newBuilder().maximumSize(Constants.MAX_SIZE)
.expireAfterWrite(Conastants.EXPIRE, TimeUnit.DAYS)
.build(key -> loadCache(key));
@Nullable
private Boolean loadCache(@NonNull String key) {
if(key.contains(Constant.UNDER_LINE)){
try {
String[] arr = key.split(Constant.UNDER_LINE);
Integer ak = Integer.parseInt(arr[0]);
String sk = arr[1];
RPCResult<Boolean> result = authService.checkSvc(ak, sk);
if(result.getSuccess()){
Boolean data = result.getData();
return data;
}
return false;
} catch (Exception e) {
log.error("{}",e);
}
}
return false;
}
思考
大家看下上述程式碼塊的寫法有沒有問題?
粗看貌似沒啥問題,但實際是有點小問題的。當進行遠端呼叫時,如果出現異常,此時布林值會返回false。這樣就可能把正確的結果給掩蓋了,比如明明都按約定的 ak,sk傳值了,結果返回鑑權失敗。
修復
那要如何修復?扯一點哲學東西,這個世界不是非黑即白,其實可能還存在灰色地帶。布林值在java的世界中,也不是就只有true或者false,當布林值為包裝類時,他還有一種狀態是null。因此可以修改為
@Nullable
private Boolean loadCache(@NonNull String key) {
if(key.contains(Constant.UNDER_LINE)){
try {
String[] arr = key.split(Constant.UNDER_LINE);
Integer ak = Integer.parseInt(arr[0]);
String sk = arr[1];
RPCResult<Boolean> result = authService.checkSvc(ak, sk);
if(result.getSuccess()){
Boolean data = result.getData();
return data;
}
return false;
} catch (Exception e) {
log.error("{}",e);
}
}
return null;
}
但這樣改就沒問題了嗎,其實還是有問題,因為null值也不是正確結果。但我們可以利用null來額外做一些異常兜底。比如出現null時,就是有問題了,我們可以對A進行友好的提示,而非返回鑑權失敗,也便於提前暴露問題,而下次請求進來時,快取會因為值為null,再次觸發遠端呼叫
總結
異常流程思考很重要。。。