.Action概述
ES提供client供集群節點或java客戶端訪問集群用。client模塊通過代理模式,將所有的操作都集成到client接口中。這樣外部調用只需要初始化client就能夠完成所有的調用功能。在每個方法后面都有一個***action來承接相應的功能。elasticsearch中的絕大部分操作都是通過相應的action,這些action在action包中。它的結構如下圖所示:

上圖是action包的部分截圖,這里面對應着各個功能的action。各個action的包也都非常類似於index。這些action的實現也非常類似,都是基礎自action,下圖是indexaction的繼承關系:

因為這些action並未真正實現相應的功能,只是一個代理,因此實現上也非常簡單。他們的主要作用是提供新建response和request的方法及對應的action名稱。還拿indexaction為例,它的方法圖如下所示:

可以看到它只是提供了兩個新建response和request的方法,及一個字NAME字段,這個NAME字段會用於后面action調用中。每個action對應的功能實現是在對應的transportAction中。

實際上***action也並非是真正的功能實現者,它只是一個代理,它的真正實現者是transport***Action.在ES中,Transport*Action 是比較核心的類集合。這里至少有兩組映射關系。
Action -> Transport*Action
Transport*Action -> *TransportHandler
對應的功能是,可以通過Action 找到對應的TransportAction,這些TransportAction 如果是query類,則會調用SearchServiceTransportAction,並且通過第二層映射找到對應的Handler,否則可能就直接通過對應的Service完成操作。
第一層映射關系由類似下面的代碼在ActionModule中完成:

第二層映射目前看來只有在查詢相關的功能才有,其他的Transport*Action 則只調用對應的Service 來完成實際的操作。類似 SearchServiceTransportAction ,可以看做是SearchService進一步封裝。如下:

2.rest請求到action的映射
對於java的Client請求,可以直接找到對應的action請求,但是ES為了提供更為通用的restful請求,通過restControl進行了由http到action的映射。
首先,每一個action在初始化時,針對自身能處理的action向restController進行注冊,以RestCreateIndexAction為例,
public RestCreateIndexAction(Settings settings, RestController controller, Client client) { super(settings, controller, client); controller.registerHandler(RestRequest.Method.PUT, "/{index}", this); controller.registerHandler(RestRequest.Method.POST, "/{index}", this); }
restController維護了幾個隊列,用來處理不同類型的http請求。
/** * Registers a rest handler to be execute when the provided method and path match the request. */ public void registerHandler(RestRequest.Method method, String path, RestHandler handler) { switch (method) { case GET: getHandlers.insert(path, handler); break; case DELETE: deleteHandlers.insert(path, handler); break; case POST: postHandlers.insert(path, handler); break; case PUT: putHandlers.insert(path, handler); break; case OPTIONS: optionsHandlers.insert(path, handler); break; case HEAD: headHandlers.insert(path, handler); break; default: throw new IllegalArgumentException("Can't handle [" + method + "] for path [" + path + "]"); } }
當httpServer收到請求時候,優先進行plugin處理,然后轉發給 RestController來處理。
public void internalDispatchRequest(final HttpRequest request, final HttpChannel channel) { String rawPath = request.rawPath(); if (rawPath.startsWith("/_plugin/")) { RestFilterChain filterChain = restController.filterChain(pluginSiteFilter); filterChain.continueProcessing(request, channel); return; } else if (rawPath.equals("/favicon.ico")) { handleFavicon(request, channel); return; } restController.dispatchRequest(request, channel); }
RestController收到請求后,如果有filter,先進行r過濾。然后進行executeHandler,最后通過channel返回操作結果
void executeHandler(RestRequest request, RestChannel channel) throws Exception { final RestHandler handler = getHandler(request); if (handler != null) { handler.handleRequest(request, channel); //根據action注冊的path,調用對應action的handleRequest方法,在該方法內通過channel返回操作結果
} else { if (request.method() == RestRequest.Method.OPTIONS) { // when we have OPTIONS request, simply send OK by default (with the Access Control Origin header which gets automatically added) channel.sendResponse(new BytesRestResponse(OK)); } else { channel.sendResponse(new BytesRestResponse(BAD_REQUEST, "No handler found for uri [" + request.uri() + "] and method [" + request.method() + "]")); } } }
