1.概述
转载:[6]elasticsearch源码深入分析——API源码分析
2.RestController的继承关系
从Node
实例化的过程中,我们知道ActionModule
是Node
提供Rest
请求功能的主要模块。RestController
的实例是在ActionModule
实例化的时候传入的重要参数之一,RestController
是API
提供服务的关键类之一,我们先从这个类开始梳理Rest API
的加载逻辑。
RestController
继承自AbstractComponent
,实现了HttpServerTransport.Dispatcher
接口。
抽象类AbstractComponent
,没什么复杂的逻辑,就是定义了一个基类Logger
,一个Deprecation
的Logger
,Deprecation
的Logger用处是打印settings
配置中不提倡的参数设定(提醒ElasticSearch
的使用者),该抽象类只有两个关于日志的方法:
- 调用
AbstractComponent
的logDeprecatedSetting(String settingName, String alternativeName)
方法就能提示启动ElasticSearch
的用户参数中的settingName
是弃用的,可以用方法中的参数alternativeName
来代替。 - 调用
AbstractComponent
的logRemovedSetting(String settingName, String alternativeName)
方法能提示用户settingName
参数已经被移除,可用alternativeName
来代替。
因为设计思路是将dispatchRequest
这样的方法设计成接口,而发送请求逻辑分组率属于HttpServerTransport
,所以将Dispatcher
接口设计成HttpServerTransport
的内部接口,这样所有的Dispatcher
的实现类都会带有HttpServerTransport
接口的标记。
HttpServerTransport
接口又实现了LifecycleComponent
接口,LifecycleComponent
接口标记了生命周期状态相关的逻辑,如下图:
其中Releasable
类是ElasticSearch
自己封装JDK1.7
中的AutoCloseable
。从LifecycleComponent
的方法中可以看出该接口主要标记了Component
的生命周期状态相关,当然还有添加和移除生命周期监听器,主要还是看LifecycleComponent
的实现类是怎么实现这些标记的逻辑的。
下面我们查看HttpServerTransport
接口的逻辑,这个接口也不复杂,在HttpServerTransport
接口中则主要配置了http
线程的线程名前缀,绑定的Address,Http信息和状态
。
在HttpServerTransport
的内部接口Dispatcher
中,主要是两个方法:
void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext)
发送request到相关处理请求程序,如果request不能被任何处理请求程序处理则直接响应给RestChannel
void dispatchBadRequest(RestRequest request, RestChannel channel, ThreadContext threadContext, Throwable cause)
发送一个失败的RestRequest,用在request是残缺的情况下。
2.1 RestController中的主要方法
梳理了RestController
的父类结构,终于到了梳理RestController
本身的时候了。RestController
中最关键的方法是:
dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext)
registerHandler(RestRequest.Method method, String path, RestHandler handler)
2.1.1 registerHadler方法
RestController
的registerHandler
方法做了哪些事呢?registerHandler
的主要功能是当注册了一个REST
处理程序后,如果提供的方法和路径之一匹配请求时,执行处理程序。
查看源码我们会发现主要做了两个操作
registerHandler
方法将BaseRestHandler
的实例注册到usageService
中,UsageService
是监控ElasticSearch
特性的服务(UsageService
的主要逻辑是统计了RestController
实例中的handler
的占用数,底层是用的LongAdder
,其适用于统计计数的场景),简而言之就是让Node
的usageService
加入对参数中handler和path
的监控。- 更新
handlers
中的参数。因为RestController
中持有一个PathTrie<MethodHandlers>
类型的handler
,每次注册都更新这个handler
里面的值。
2.1.2 dispatchRequest方法
这个方法是实现了Dispatcher
接口中的dispatchRequest
方法。
由于ElasticSearch
没有用到任何WEB框架,rest请求底层都是使用Netty
实现的,收到的请求都是从ElasticSearch
的transport-netty4
模块里面发送给ElasticSearch
的核心的。
transport-netty4
模块的Netty4HttpRequestHandler
类的channelRead0(ChannelHandlerContext ctx, Object msg)
方法接受到其请求,然后发送给Netty4HttpServerTransport
的dispathchRequest
方法Netty4HttpServerTransport
再转发给RestController
的DispatchRequest
方法RestController
中dispatchRequest
,遍历所有可能的处理程序,发送请求:
Iterator<MethodHandlers> allHandlers = getAllHandlers(request);
for (Iterator<MethodHandlers> it = allHandlers; it.hasNext(); ) {
final Optional<RestHandler> mHandler = Optional.ofNullable(it.next()).flatMap(mh -> mh.getHandler(request.method()));
requestHandled = dispatchRequest(request, channel, client, mHandler);
if (requestHandled) {
break;
}
}
如果返回的requestHandled
为false
,则返回失败的handleBadRequest(request, channel);
3.CAT API
3.1 cat aliases API
aliases
显示有关当前配置的别名的信息,包括过滤器和路由信息。
GET /_cat/aliases?v
可能的响应:
alias index filter routing.index routing.search
alias1 test1 - - -
alias2 test1 * - -
alias3 test1 - 1 1
alias4 test1 - 2 1,2
输出显示alias2
已经配置了一个过滤器,以及alias3
和alias4
中的特定路由配置。
如果只想获取有关特定别名的信息,则可以使用逗号分隔格式指定别名作为URL参数,例如,/_cat/aliases/aliases/alias1,alias2
REST请求是通过准备一个channel
消费者(RestChannelConsumer
)来处理的,Node
在接收到aliases catAPI
请求后,转发到RestAliasAction的doCatRequest
方法,该方法会先确定这个请求是否是来自本地。RestAliasAction类的doCatRequest
方法会返回一个RestChannelConsumer
。
RestAliasAction
类的doCatRequest
方法接收两个参数RestRequest
和NodeClient
。
这里的NodeClient是在本地节点上执行操作的Client。继承关系如下图:
其中Client
接口提供了一个用于对集群执行actions
或操作的接口。客户可以从一个org.elasticsearch.node.node
检索开始,或远程连接使用一个或多个节点org.elasticsearch.client.transport.transportclient
。
而NodeClient
的admin
方法是取得AbstractClient.Admin.IndicesAdmin
实例,通过参数“索引别名请求(getAliasesRequest)”
和“通知结果监听器(new RestResponseListener<GetAliasesResponse>(channel))”
来获取特定索引或按名称存在的特定索引别名。