熟悉Dubbo的同學或朋友,都會知道,一般dubbo的service層都是一些通用的,無狀态的服務。但是在某些特殊的需求下,我們又需要傳遞一些上下文環境,打個不恰當的比方,例如需要在每次調用dubbo的服務的時候,記錄一下使用者名或者需要知道sessionid等。
解決辦法1
如果是在項目設計的時候就意識到這一點的話,就好辦,把所有的dubbo服務請求的參數都封裝一個公共的父類,把一些上下文環境在放在父類的屬性中。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicGcq5SNyMTM3EmMiF2N2E2N4UWY2IDM0MDNwQWZ2MzMzcDOz8CX5d2bs92Yl1iclB3bsVmdlR2LcNWaw9CXt92Yu4GZjlGbh5yYjV3Lc9CX6MHc0RHaiojIsJye.jpg)
這樣做的好處就是,dubbo接口的參數都統一的,在Dubbo中可以做一些統一的處理(例如把上下文環境取出來,放在ThreadLocal中)。
解決辦法2
但是并不是所有的項目一開始就有這個需求的,但是突然有一天他猝不及防的出現了(比如本人就接到要使用多資料,每次前端請求的時候根據參數選擇使用的資料庫),如果項目已經基本定型的情況下,再改造成上面的解決辦法,改動量太大(不怕麻煩的也可以,但是本人就比較懶)。
改造方案
隻需要在調用方加一個切面,在服務方加一個filter切面
代碼如下
/**
* 在調用service的接口之前,加入一些dubbo的隐式參數
* Created by binghe
*/
@Aspect
@Component
public class DubboServiceContextAop {
@Pointcut("execution(* com.打碼.打碼..service.api.*.*(..))")
public void serviceApi() {
}
@Before("serviceApi()")
public void dubboContext(JoinPoint jp) {
Map<String, String> context = new HashMap<>();
// todo you want do
RpcContext.getContext().setAttachments(context);
}
}
本項目service的package命名都是 com.打碼.打碼.子產品名.service.api 是以隻需要一個execution就行了,這也是養成統一的包命名的好處
Dubbo Filter
代碼如下,很簡單
public class DubboContextFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String var= RpcContext.getContext().getAttachment(從Aop中放入的);
//todo 其他相關處理
return invoker.invoke(invocation);
}
怎麼寫Dubbo Filter
第一步:建立一個類實作Filter接口
如上面的DubboContextFilter
注意是com.alibaba.dubbo.rpc.Filter
第二步:在resources中建立檔案
META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
注意是 META-INF檔案下的dubbo檔案夾下的"com.alibaba.dubbo.rpc.Filter"檔案
并在裡面加入,也就是第一步中建立的類的路徑
dubboContextFilter=com.打碼.打碼.打碼.打碼.打碼.DubboContextFilter
第三步:在配置檔案中加入
<dubbo:provider filter="dubboContextFilter" />
小結
其實dubbo内置了一些filter,我們可以自定義自己的filter來完成一些和業務流程無關的邏輯,例如可以寫IP白名單等等