根據IP動態路由調用Dubbo服務

一、前言
前面我們探討了如何獲取某一個Dubbo的服務的提供者列表,本節我們探討如何使用Dubbo的擴展,實現指定IP調用。
二、實現
在Dubbo中集羣容錯策略Cluster是SPI擴展接口,DUbbo框架提供了豐富的集羣容錯策略實現,本節我們就基於擴展接口實現指定IP調用功能。
首先我們實現擴展接口Cluster:
[Java] 純文本查看 複製代碼
1
2
3
4
5
6
public class MyCluster implements Cluster{
   @Override
   public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
       return new MyClusterInvoker(directory);
   }
}
然後我們看自己實現的MyClusterInvoker
[Java] 純文本查看 複製代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public class MyClusterInvoker<T> extends MyAbstractClusterInvoker<T> {
 
 
 
 public MyClusterInvoker(Directory<T> directory) {
 
     super(directory);
 
 }
 
@Override
 protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance)
         throws RpcException {
     //1.查看是否設置了指定ip
     String ip = (String) RpcContext.getContext().get("ip");
     if (StringUtils.isBlank(ip)) {
         throw new RuntimeException("ip is blank ");
     }
     //2.檢查是否有可用invoker
     checkInvokers(invokers,invocation);
     //3.根據指定ip獲取對應invoker
     Invoker<T> invoked = invokers.stream().filter(invoker -> invoker.getUrl().getHost().equals(ip))
             .findFirst().orElse(null);
     //4.檢查是否有可用invoker
 
     if(null == invoked) {
 
         throw new RpcException(RpcException.NO_INVOKER_AVAILABLE_AFTER_FILTER,
 
                 "Failed to invoke the method " + invocation.getMethodName() + " in the service "
 
                         + getInterface().getName() + ". No provider available for the service "
 
                         + directory.getUrl().getServiceKey() + " from ip " + ip + " on the consumer "
 
                         + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion()
 
                         + ". Please check if the providers have been started and registered.");
 
    }
 
     //5.發起遠程調用,失敗則拋出異常
 
     try {
         return invoked.invoke(invocation);
 
     } catch (Throwable e) {
 
         if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
 
             throw (RpcException) e;
 
         }
 
         throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0,
                 "Fail invoke providers " + (invoked != null?invoked.getUrl():"")+ " " + loadbalance.getClass().getSimpleName()
                         + " select from all providers " + invokers + " for service " + getInterface().getName()
                         + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost()
                         + " use dubbo version " + Version.getVersion()
                         + ", but no luck to perform the invocation. Last error is: " + e.getMessage(),
                 e.getCause() != null ? e.getCause() : e);
     }
 }
}
  • 如上代碼1,我們從RpcContext.getContext()獲取了屬性值ip,如果指定了改值說明指定了ip,
  • 代碼2則檢查是否有可用的服務提供者,如果沒有則拋出異常。
  • 代碼3變量invokers列表查找指定IP對應的Invoker
  • 代碼4 檢查是否有對應IP對應的Invoker,沒有則拋出異常。
  • 代碼5 具體使用選擇的invoker發起遠程調用。

注意我們還修改了框架的AbstractClusterInvoker爲MyAbstractClusterInvoker:

 

[Java] 純文本查看 複製代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
<font style="color:rgb(102, 102, 102)"><font face="Arial, Helvetica, sans-serif">public Result invoke(final Invocation invocation) throws RpcException {
  checkWhetherDestroyed();
  // binding attachments into invocation.
  Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
  if (contextAttachments != null && contextAttachments.size() != 0) {
      ((RpcInvocation) invocation).addAttachments(contextAttachments);
  }
  List<Invoker<T>> invokers = list(invocation);
    LoadBalance loadbalance = null;//initLoadBalance(invokers, invocation);
  RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
  return doInvoke(invocation, invokers, loadbalance);
}
</font></font>

 

這裏我們把 LoadBalance loadbalance = initLoadBalance(invokers, invocation);
修改爲了 LoadBalance loadbalance = null;因爲我們不需要負載均衡了。

然後在消費端調用時候進行下面設置就可以指定ip調用了。


//設置集羣容錯策略爲我們自己的
referenceConfig.setCluster("myCluster");
//指定ip,企圖讓ip爲30.10.67.231的服務提供者來處理服務
RpcContext.getContext().set("ip", "30.10.67.231");
   
三、總結

Dubbo是一個高度可擴充的框架,基於SPI的擴展接口,我們可以根據需要定製我們自己的實現,本文我們則基於集羣容錯策略實現了基於ip調用的擴展。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章