本文基于dubbo v2.6.x
1.标簽路由介紹
官方對于标簽路由的解釋(官方文檔位址:連結):
一次 dubbo 調用能夠根據請求攜帶的 tag 标簽智能地選擇對應 tag 的服務提供者進行調用。
這個标簽路由可以了解為給應用或者是一次調用打标簽,然後具有相同标簽的會被通路到,如果沒有相同标簽的服務提供者,你隻要沒有設定 dubbo.force.tag為true也就是強制使用标簽,它就會去标簽為null的服務提供者,dubbo管這個操作叫服務降級。
其實這個标簽路由是dubbo自動裝配的,不需要咱們配置使用哪種路由,它會在setRouters時候自動給你放到路由清單中。我們來看下
我們來看下使用标簽路由怎樣配置:
服務提供者方:
注解:直接在@Service注解上配置tag 屬性:
@Service(tag = "red")
xml:
服務調用者方:
請求标簽的作用域為每一次 invocation,使用 attachment 來傳遞請求标簽,注意儲存在 attachment 中的值将會在一次完整的遠端調用中持續傳遞,得益于這樣的特性,我們隻需要在起始調用時,通過一行代碼的設定,達到标簽的持續傳遞。
2. TagRouter源碼解析
先看下TagRouter的class定義:
可以看到TagRouter 繼承AbstractRouter ,這個就沒啥好說的了,排序規則AbstractRouter 幫他完成了。
接着看下類成員與構造方法:
private static final int DEFAULT_PRIORITY = 100;
private static final URL ROUTER_URL = new URL("tag", Constants.ANYHOST_VALUE, 0, Constants.ANY_VALUE).addParameters(Constants.RUNTIME_KEY, "true");
public TagRouter() {
this.url = ROUTER_URL;
// 擷取優先級
this.priority = url.getParameter(Constants.PRIORITY_KEY, DEFAULT_PRIORITY);
}
需要關注的是靜态成員ROUTER_URL 添加了一個屬性值,runtime=true,也就是支援運作時進行路由過濾。構造方法中就是指派了一下路由url與擷取了優先級priority,預設是100。
最後我們來看下route方法
@Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
// filter
List<Invoker<T>> result = new ArrayList<Invoker<T>>();
// Dynamic param
// 從上下文中擷取dubbo.tag 擴充屬性值标簽
String tag = RpcContext.getContext().getAttachment(Constants.TAG_KEY);
// Tag request
if (!StringUtils.isEmpty(tag)) {// 如果tag标簽不是空
// Select tag invokers first
for (Invoker<T> invoker : invokers) {// 與服務提供者invoker的tag 做對比
if (tag.equals(invoker.getUrl().getParameter(Constants.TAG_KEY))) {
result.add(invoker);// tag标簽相等的 設定到結果清單中
}
}
}
/**
* request.tag=red 時優先選擇 tag=red 的 provider。若叢集中不存在與請求标記對應的服務,可以降級請求 tag=null 的 provider,即預設 provider。
*
* request.tag=null 時,隻會比對 tag=null 的 provider。即使叢集中存在可用的服務,若 tag 不比對就無法調用,這與規則1不同,攜帶标簽的請求可以降級通路到無标簽的服務,但不攜帶标簽/攜帶其他種類标簽的請求永遠無法通路到其他标簽的服務。
*/
// If Constants.REQUEST_TAG_KEY unspecified or no invoker be selected, downgrade to normal invokers
if (result.isEmpty()) {// 如果results 是空的話
// Only forceTag = true force match, otherwise downgrade
// 擷取force标簽 dubbo.force.tag 屬性值
String forceTag = RpcContext.getContext().getAttachment(Constants.FORCE_USE_TAG);
// 如果forceTag 是空或者是forceTag
if (StringUtils.isEmpty(forceTag) || "false".equals(forceTag)) {
for (Invoker<T> invoker : invokers) {
//若叢集中不存在與請求标記對應的服務,可以降級請求 tag=null 的 provider,即預設 provider。
if (StringUtils.isEmpty(invoker.getUrl().getParameter(Constants.TAG_KEY))) {
result.add(invoker);
}
}
}
}
return result;
}
在route方法中先是擷取調用這dubbo.tag 屬性值,如果這個屬性值不是空的話,就循環周遊服務提供者清單,找到與服務調用者dubbo.tag 屬性值相等的服務提供者添加到result集合中。
如果最後result集合沒有服務提供者,就擷取dubbo.force.tag 屬性值(這個屬性值表示是否強制使用tag),如果沒有配置這個屬性值或者是false,就将dubbo.tag 屬性值 是null的服務提供者添加到result集合中,然後傳回。
下面引用一段官網的解釋(關于服務降級):
1.request.tag=red 時優先選擇 tag=red 的 provider。若叢集中不存在與請求标記對應的服務,可以降級請求 tag=null 的 provider,即預設 provider。
2.request.tag=null 時,隻會比對 tag=null 的 provider。即使叢集中存在可用的服務,若 tag 不比對就無法調用,這與規則1不同,攜帶标簽的請求可以降級通路到無标簽的服務,但不攜帶标簽/攜帶其他種類标簽的請求永遠無法通路到其他标簽的服務。