Directory代表多個(gè)Invoker,可以把它看成List<Invoker>,但與List不同的是,它的值可能是動(dòng)態(tài)變化的,比如注冊(cè)中心推送變更。Cluster將Directory中的多個(gè)Invoker偽裝成一個(gè)Invoker,對(duì)上層透明,偽裝過(guò)程包含了容錯(cuò)邏輯,調(diào)用失敗后,重試另一個(gè)。
上面是文檔上對(duì)Directory的解釋。
Directory接口
Directory接口繼承了Node接口:
public interface Directory<T> extends Node {
//獲取服務(wù)類(lèi)型
Class<T> getInterface();
//invoker列表,服務(wù)的列表
List<Invoker<T>> list(Invocation invocation) throws RpcException;
}
AbstractDirectory
默認(rèn)實(shí)現(xiàn)為AbstractDirectory:
public abstract class AbstractDirectory<T> implements Directory<T> {
// 日志輸出
private static final Logger logger = LoggerFactory.getLogger(AbstractDirectory.class);
//服務(wù)url
private final URL url ;
private volatile boolean destroyed = false;
//消費(fèi)者url
private volatile URL consumerUrl ;
//路由
private volatile List<Router> routers;
public AbstractDirectory(URL url) {
this(url, null);
}
public AbstractDirectory(URL url, List<Router> routers) {
this(url, url, routers);
}
public AbstractDirectory(URL url, URL consumerUrl, List<Router> routers) {
if (url == null)
throw new IllegalArgumentException("url == null");
this.url = url;
this.consumerUrl = consumerUrl;
setRouters(routers);
}
//對(duì)list方法的默認(rèn)實(shí)現(xiàn)
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (destroyed){
throw new RpcException("Directory already destroyed .url: "+ getUrl());
}
//獲取Invoker列表的具體實(shí)現(xiàn)由具體子類(lèi)實(shí)現(xiàn)
List<Invoker<T>> invokers = doList(invocation);
//路由
List<Router> localRouters = this.routers; // local reference
if (localRouters != null && localRouters.size() > 0) {
for (Router router: localRouters){
try {
if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, true)) {
//路由
invokers = router.route(invokers, getConsumerUrl(), invocation);
}
} catch (Throwable t) {
logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
}
}
}
return invokers;
}
public URL getUrl() {
return url;
}
public List<Router> getRouters(){
return routers;
}
public URL getConsumerUrl() {
return consumerUrl;
}
public void setConsumerUrl(URL consumerUrl) {
this.consumerUrl = consumerUrl;
}
//構(gòu)造中調(diào)用的設(shè)置路由的方法
protected void setRouters(List<Router> routers){
// copy list
routers = routers == null ? new ArrayList<Router>() : new ArrayList<Router>(routers);
// append url router
String routerkey = url.getParameter(Constants.ROUTER_KEY);
//指定了router,就使用制定的router來(lái)獲取擴(kuò)展實(shí)現(xiàn)
if (routerkey != null && routerkey.length() > 0) {
RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey);
routers.add(routerFactory.getRouter(url));
}
// append mock invoker selector
routers.add(new MockInvokersSelector());
Collections.sort(routers);
this.routers = routers;
}
public boolean isDestroyed() {
return destroyed;
}
public void destroy(){
destroyed = true;
}
//子類(lèi)實(shí)現(xiàn)具體的獲取invoker列表
protected abstract List<Invoker<T>> doList(Invocation invocation) throws RpcException ;
}
Directory具體的實(shí)現(xiàn)有兩個(gè)RegistryDirectory注冊(cè)目錄服務(wù)和StaticDirectory靜態(tài)目錄服務(wù)。
RegistryDirectory
RegistryDirectory實(shí)現(xiàn)了NotifyListener接口,因此他本身也是一個(gè)監(jiān)聽(tīng)器,可以在服務(wù)變更時(shí)接受通知,消費(fèi)方要調(diào)用遠(yuǎn)程服務(wù),會(huì)向注冊(cè)中心訂閱這個(gè)服務(wù)的所有的服務(wù)提供方,訂閱的時(shí)候會(huì)調(diào)用notify方法,進(jìn)行invoker實(shí)例的重新生成,也就是服務(wù)的重新引用。在服務(wù)提供方有變動(dòng)時(shí),也會(huì)調(diào)用notify方法,有關(guān)notify方法在Dubbo中訂閱和通知解析那篇文章中已經(jīng)解釋,不做重復(fù)。subscribe方法也不做重復(fù)解釋。
StaticDirectory
靜態(tài)目錄服務(wù)。