1. 程式人生 > >使用Dubbo的SPI擴充套件機制實現自定義LoadBalance——方法一 修改Dubbo原始碼

使用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、分散式、高併發等架構技術,歡迎進群一起討論哦!專用於學習交流技術、分享面試機會,拒絕廣告,我也會在群內不定