由於項目需求特殊,需要在dubbo中實現一種能指定遠程地址的分發機制,剛開始想在直連的配置上解決,後來發現對於已經加載了dubbo xml配置的spring容器中是無法在代碼層面進行有效的修改的(因爲貌似會重新加載xml文件中原有的配置記錄),另一方面,這種做法會產生併發衝突的隱患。後來經同事提醒,使用了dubbo留出來的擴展點的方法實現了這個功能,也就是實現了AbstractLoadBalance接口,並重寫了doSelect方法,在doSelect方法實現中,根據調度服務方法傳進的參數也就是指定的遠程主機的ip地址和端口進行了過濾,最終返回滿足該條件的Invoker作爲最終的返回值給調用端。
實現過程相對簡單,但是網上資料並不多,簡單記錄下:
1. 首先要繼承AbstractLoadBalance並重寫select方法,並且注意包要和其他dubbo已經提供的LoadBalance類同一級目錄,比如我實現的一個子類:
packagecom.alibaba.dubbo.rpc.cluster.loadbalance;
import java.io.File;
import java.util.List;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
importcom.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
/**
*
* @author : zhengrf1
* @date 創建時間:2017年11月1日 下午5:07:15
* @version 1.0
* @parameter
* @since
* @return
*/
public class AppointLoadBalance extendsAbstractLoadBalance {
/*@author : zhengrf1
* @date 創建時間:2017年11月1日 下午5:07:16
* @seecom.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance#doSelect(java.util.List,com.alibaba.dubbo.common.URL, com.alibaba.dubbo.rpc.Invocation)
*/
@Override
protected<T> Invoker<T> doSelect(List<Invoker<T>> arg0, URLarg1, Invocation arg2) {
//TODO Auto-generated method stub
System.out.println("helloworld"+arg2.getMethodName()+arg2.getArguments().length+arg2.getArguments()[0].toString());
for(Invoker<T>invoker : arg0){
System.out.println(invoker.getUrl().getAddress()+invoker.getUrl().getHost()+invoker.getUrl().getPort());
if(invoker.getUrl().getHost().equals(arg2.getArguments()[2].toString())){
returninvoker;
}
}
returnnull;
}
}
--在該類邏輯中,取到了調度服務接口的第三個參數也就是指定的ip和端口,並且以此來過濾所有的invoker,返回滿足條件的invoker。並且注意包聲明:package com.alibaba.dubbo.rpc.cluster.loadbalance;
2.在dubbotisson-2.5.3.2.jar下面的META-INF/dubbo/internal/目錄下找到com.alibaba.dubbo.rpc.cluster.LoadBalance文件,並且在該文件最後一行中添加:
Appoint= com.alibaba.dubbo.rpc.cluster.loadbalance.AppointLoadBalance
--我是直接修改了dubbotisson-2.5.3.2.jar下的該文件,並重新加入項目的依賴外包,網上說比較規範的做法是自己創建一個jar包,並且在同樣的目錄層次下創建同名的文件,並把這行配置內容寫進去。這樣,dubbo啓動時會自動掃描所有com.alibaba.dubbo.rpc.cluster.LoadBalance文件進行合併,另外也可以同時把自己實現的AbstractLoadBalance子類加入jar包,當然這種做法我沒真正實踐過。
3.在xml配置中,配置service層:
<dubbo:serviceinterface="operatingPlatform.DispatchServer" ref="DispatchServerImpl"executes="20" loadbalance="appoint"/>
--默認的loadbalance是RandomLoadBalance,所以要顯式修改成自己的。
---到此爲止,對於dubbo的均衡策略就完成了。但是隻截取這一層看起來有點糊塗,所以最好明白整個dubbo的路由均衡機制。
--簡單來說,就是Cluster的子類通過自己持有的FailoverClusterInvoker,首先調用Directory的子類的list方法 獲取所有符合條件的Invoker,並放置在List容器中,然後調用Router的子類調用route方法過濾掉不滿足路由條件的Invoker,然後調用LoadBalance的子類的Select方法,選中最後需要調用的Invoker,最後調用該Invoker的Invoke方法實現遠程調用。
可以通過下面的異常報錯流程看出一二:
Exception in thread "main"java.lang.NullPointerException
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.doselect(AbstractClusterInvoker.java:135)
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.select(AbstractClusterInvoker.java:115)
atcom.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:73)
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:227)
atcom.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
atcom.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
atcom.alibaba.dubbo.common.bytecode.proxy0.dispatch(proxy0.java)
atoperatingPlatform.DispatchClient.main(DispatchClient.java:31)