使用Dubbo的SPI擴充套件機制實現自定義LoadBalance——方法一 修改Dubbo原始碼
一. 拉取原始碼
到Dubbo官網 https://github.com/apache/incubator-dubbo/tree/2.5.x 下載原始碼,解壓。
二. 匯入IDEA
選擇解壓後的原始碼目錄,一路點選next
三. 實現LoadBalance介面
在loadbalance包中,建立一個class,並實現LoadBalance介面。 如下:建立SameSessionIdLoadBalance類實現LoadBalance介面
/** * 儲存sessionId和服務地址的對映關係 * invoker.getUrl().getAddress()可以獲取到該invoker的服務地址資訊 * sessinoId存在,那麼就返回sessionId所在的invoker * sessionId不存在,那麼就輪訓的找一個invoker返回 */ public class SameSessionIdLoadBalance implements LoadBalance { private final static Logger logger = LoggerFactory.getLogger(SameSessionIdLoadBalance.class); private Map<String,String> sessionIdAddress = new ConcurrentHashMap<String,String>(256); private AtomicInteger index = new AtomicInteger(0); @Override public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException { Invoker result = null; //約定方法的第一個引數就是sessionId String sessionId = (String) invocation.getArguments()[0]; if(!sessionIdAddress.containsKey(sessionId)){ result = invokers.get(index.getAndIncrement()%invokers.size()); sessionIdAddress.put(sessionId,result.getUrl().getAddress()); }else{ String destAddress = sessionIdAddress.get(sessionId); for (Invoker<T> invoker : invokers) { if(invoker.getUrl().getAddress().equals(destAddress)){ result = invoker; } } } logger.info("sesisonId: " + sessionId + " ,method: " + invocation.getMethodName() + " ,select " + result.getUrl().getAddress() + " broker"); return result; } }
四. 新增配置資訊
新增的samesessionloadbalance就是該負載均衡的名字。
五. 構建安裝原始碼
開啟終端控制檯執行mvn clean install -Dmaven.test.skip
最後會在maven的本地倉庫中生成jar包
可以通過360解壓縮檢視jar包中的class檔案,看看我們的程式碼是否編譯進去了。
六. 測試程式碼
公共介面
public interface DemoService { String saySomething(String msg); }
provider實現該介面
public class DemoServiceImpl implements DemoService { public String saySomething(String msg) { //每次啟動 把20880改成相應的埠 方便觀察結果。 return "this is 20880 " + msg; } }
Provider啟動
public class Provider { public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:provider.xml"); ctx.start(); System.in.read(); } }
provider.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 提供方應用資訊,用於計算依賴關係 --> <dubbo:application name="hello-world-app" /> <!-- 使用zookeeper註冊中心暴露服務地址 --> <dubbo:registry address="zookeeper://10.130.41.36:2181"/> <!-- 用dubbo協議在20880埠暴露服務 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 宣告需要暴露的服務介面 --> <!--samesessionloadbalance--> <dubbo:service interface="com.xxx.testdubbo.DemoService" ref="demoService" loadbalance="samesessionloadbalance"/> <!-- 和本地bean一樣實現服務 --> <bean id="demoService" class="com.xxx.testdubbo.provider.DemoServiceImpl" /> </beans>
Consumer啟動
public class Customer { public static void main(String[] args){ ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:customer.xml"); DemoService ds = (DemoService) ctx.getBean("demoService"); System.out.println(ds.saySomething("001")); } }
customer.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 消費方應用名,用於計算依賴關係,不是匹配條件,不要與提供方一樣 --> <dubbo:application name="consumer-of-helloworld-app" /> <!-- 使用zookeeper註冊中心暴露發現服務地址 --> <dubbo:registry address="zookeeper://10.130.41.36:2181" /> <!-- 生成遠端服務代理,可以和本地bean一樣使用demoService --> <dubbo:reference id="demoService" interface="com.xxx.testdubbo.DemoService" /> </beans>
七.啟動例項測試
Dubbo使用一些容錯機制,裡面會有一些判斷。如下圖所示:
當invoker只有一個那麼就直接返回
當invoker有兩個那麼使用輪序機制
當有三個或三個以上的invoker時,才會觸發loadbalance機制。
所以我們要啟動三個Provider
更改provider.xml中Dubbo的監聽埠為20880,20881,20882分別啟動例項
在DemoServiceImpl中,每啟動一個Provider例項,該方法返回相應的ip+埠號資訊。
最後啟動Customer,觀察埠號結果。
八. 除錯自定義LoadBalance
在專案裡面一定引用了Dubbo的jar包,找到SameSessionIdLoadBalance檔案,下斷點,Consumer除錯執行就可以了。
總結
歡迎關注+點選連結加入群聊【架構華山論劍836442475】:https://jq.qq.com/?_wv=1027&k=59k1QB9,進我的私人群討論技術和學習!
群內有大牛架構師分享經驗,Dubbo、Redis、Netty、zookeeper、Spring cloud、分散式、高併發等架構技術,歡迎進群一起討論哦!專用於學習交流技術、分享面試機會,拒絕廣告,我也會在群內不定