solr-6.1.0源码分析---2

solr源码分析—doFilter

本章开始分析SolrDispatchFilter的doFilter函数,该函数被tomcat等框架调用。继续申明一下,为了方便分析和查看,文章的代码省略了一些不重要的部分。

SolrDispatchFilter::doFilter

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException {

    ...

    HttpSolrCall call = getHttpSolrCall((HttpServletRequest) request, (HttpServletResponse) response, retry);
    ExecutorUtil.setServerThreadFlag(Boolean.TRUE);
    Action result = call.call();
    switch (result) {
       case PASSTHROUGH:
         chain.doFilter(request, response);
         break;
        case RETRY:
          doFilter(request, response, chain, true);
          break;
        case FORWARD:
          request.getRequestDispatcher(call.getPath()).forward(request, response);
          break;
    }

    ...

  }

doFilter首先调用getHttpSolrCall创建HttpSolrCall,HttpSolrCall的call函数根据请求路径获取相应的处理类进行处理,最后返回处理结果。
HttpSolrCall的构造函数很简单,往下看其call函数。

SolrDispatchFilter::doFilter->HttpSolrCall::call

  public Action call() throws IOException {

    init();

    HttpServletResponse resp = response;
    switch (action) {
      case ADMIN:
        handleAdminRequest();
        return RETURN;
      ...
    }

    ...

  }

init函数根据请求路径获取对应的处理类Handler,并将请求HttpServletRequest封装成一个SolrQueryRequest。下面假设请求路径在admin下,此时action为Admin,因此通过handleAdminRequest函数处理admin路径下的请求。

init

SolrDispatchFilter::doFilter->HttpSolrCall::call->init

  private void init() throws Exception {
    Aliases aliases = null;
    String corename = "";
    String origCorename = null;

    req.setAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE, new RTimerTree());
    req.setAttribute("org.apache.solr.CoreContainer", cores);
    path = req.getServletPath();

    int idx = path.indexOf(':');
    boolean usingAliases = false;

    handler = cores.getRequestHandler(path);
    if (handler != null) {
      solrReq = SolrRequestParsers.DEFAULT.parse(null, path, req);
      solrReq.getContext().put(CoreContainer.class.getName(), cores);
      requestType = RequestType.ADMIN;
      action = ADMIN;
      return;
    } else {

      ...

    }

    ...
  }

getRequestHandler根据请求路径path获取对应的Handler。DEFAULT默认为SolrRequestParsers,其parse函数将请求HttpServletRequest提取出有效信息封装成一个SolrQueryRequest,然后向其添加相当于环境信息CoreContainer并返回。

SolrDispatchFilter::doFilter->HttpSolrCall::call->init->CoreContainer::getRequestHandler

  public SolrRequestHandler getRequestHandler(String path) {
    return RequestHandlerBase.getRequestHandler(path, containerHandlers);
  }

  public static SolrRequestHandler getRequestHandler(String handlerName, PluginBag<SolrRequestHandler> reqHandlers) {
    if(handlerName == null) return null;
    SolrRequestHandler handler = reqHandlers.get(handlerName);
    int idx = 0;
    if(handler == null) {
      for (; ; ) {
        idx = handlerName.indexOf('/', idx+1);
        if (idx > 0) {
          String firstPart = handlerName.substring(0, idx);
          handler = reqHandlers.get(firstPart);
          if (handler == null) continue;
          if (handler instanceof NestedRequestHandler) {
            return ((NestedRequestHandler) handler).getSubHandler(handlerName.substring(idx));
          }
        } else {
          break;
        }
      }
    }
    return handler;
  }

getRequestHandler根据请求路径path获取对应的处理类Handler,这里假设路径为/admin/core,则获取到CoreAdminHandler。假设一开始在reqHandlers中没有获取到Handler,则可能路径过长,这时就从左往右截取路径,直到找到对应的Handler返回,或者继续通过getSubHandler获取子Handler。

SolrDispatchFilter::doFilter->HttpSolrCall::call->init->SolrRequestParsers::parse

  public SolrQueryRequest parse( SolrCore core, String path, HttpServletRequest req ) throws Exception{
    SolrRequestParser parser = standard;

    ArrayList<ContentStream> streams = new ArrayList<>(1);
    SolrParams params = parser.parseParamsAndFillStreams( req, streams );
    SolrQueryRequest sreq = buildRequestFrom(core, params, streams, getRequestTimer(req), req);

    sreq.getContext().put(PATH, RequestHandlers.normalize(path));
    sreq.getContext().put("httpMethod", req.getMethod());

    return sreq;
  }

这里的standard是StandardRequestParser,其parseParamsAndFillStreams函数解析request中的参数存入map结构params中。buildRequestFrom函数根据请求信息params创建SolrQueryRequest,然后向其添加请求路径信息和请求方法信息,最后返回。

SolrDispatchFilter::doFilter->HttpSolrCall::call->init->SolrRequestParsers::parse->buildRequestFrom

  private SolrQueryRequest buildRequestFrom(SolrCore core, SolrParams params, Collection<ContentStream> streams, RTimerTree requestTimer, final HttpServletRequest req) throws Exception {

    ...

    SolrQueryRequestBase q = new SolrQueryRequestBase(core, params, requestTimer) {
      @Override
      public Principal getUserPrincipal() {
        return req == null ? null : req.getUserPrincipal();
      }
    };
    return q;
  }

buildRequestFrom创建一个SolrQueryRequestBase封装请求信息并返回。

假设请求路径在admin下,根据前面的分析,solr会调用handleAdminRequest函数处理这部分请求。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest

  private void handleAdminRequest() throws IOException {
    SolrQueryResponse solrResp = new SolrQueryResponse();
    SolrCore.preDecorateResponse(solrReq, solrResp);
    handler.handleRequest(solrReq, solrResp);
    SolrCore.postDecorateResponse(handler, solrReq, solrResp);

    QueryResponseWriter respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get(solrReq.getParams().get(CommonParams.WT));
    if (respWriter == null) respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get("standard");
    writeResponse(solrResp, respWriter, Method.getMethod(req.getMethod()));
  }

preDecorateResponse向SolrQueryResponse中添加头部结构,并生成一些日志方面的信息。
假设这里的handler为CoreAdminHandler,handleRequest函数是处理请求的主要函数。
postDecorateResponse向SolrQueryResponse的头部添加信息,例如请求处理是否成功,处理时间等。
再往下根据请求参数获得QueryResponseWriter,假设需要获得的是json返回结果,则获得JsonResponseWriter,默认“standard”会获得XMLResponseWriter。最后调用writeResponse写入返回信息。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest->CoreAdminHandler::handleRequest

  public void handleRequest(SolrQueryRequest req, SolrQueryResponse rsp) {

    ...

    req.getContext().remove(USEPARAM);
    rsp.setHttpCaching(httpCaching);
    handleRequestBody( req, rsp );

    ...
  }

handleRequest进而通过handleRequestBody处理请求。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest->CoreAdminHandler::handleRequest->handleRequestBody

  public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {

    ...

    CoreAdminOperation op = opMap.get(req.getParams().get(ACTION, STATUS.toString()).toLowerCase(Locale.ROOT));
    final CallInfo callInfo = new CallInfo(this, req, rsp, op);
    callInfo.call();
  }

  void call() throws Exception {
    op.call(this);
  }

根据请求参数的ACTION的值从opMap中获取CoreAdminOperation,封装成CallInfo并调用其call函数进行处理。CoreAdminHandler在创建时会执行静态代码,

  static {
    for (CoreAdminOperation op : CoreAdminOperation.values())
      opMap.put(op.action.toString().toLowerCase(Locale.ROOT), op);
  }

到这里就不往下看,下一章开始再往下看具体的处理函数。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest->writeResponse

  private void writeResponse(SolrQueryResponse solrRsp, QueryResponseWriter responseWriter, Method reqMethod)
      throws IOException {

    final String ct = responseWriter.getContentType(solrReq, solrRsp);
    response.setContentType(ct);

    OutputStream out = new CloseShieldOutputStream(response.getOutputStream()); 
    QueryResponseWriterUtil.writeQueryResponse(out, responseWriter, solrReq, solrRsp, ct);

  }

首先通过getContentType获得ContentType,设置进response中,然后调用QueryResponseWriterUtil的writeQueryResponse函数写入返回信息。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest->writeResponse->QueryResponseWriterUtil::writeQueryResponse

  public static void writeQueryResponse(OutputStream outputStream,
      QueryResponseWriter responseWriter, SolrQueryRequest solrRequest,
      SolrQueryResponse solrResponse, String contentType) throws IOException {

    OutputStream out = new OutputStream() {
      @Override
      public void write(int b) throws IOException {
        outputStream.write(b);
      }
      @Override
      public void flush() throws IOException {

      }
    };
    Writer writer = buildWriter(out, ContentStreamBase.getCharsetFromContentType(contentType));
    responseWriter.write(writer, solrRequest, solrResponse);
    writer.flush();
  }

buildWriter创建FastWriter,内部封装了根据编码类型创建的输出流OutputStreamWriter。接下来调用JSONResponseWriter的write进行写。最后缓存保存的是JSON格式的返回信息,将数据flush出去。

SolrDispatchFilter::doFilter->HttpSolrCall::call->handleAdminRequest->writeResponse->QueryResponseWriterUtil::writeQueryResponse->

  public void write(Writer writer, SolrQueryRequest req, SolrQueryResponse rsp) throws IOException {
    JSONWriter w = new JSONWriter(writer, req, rsp);
    w.writeResponse();
    w.close();
  }

  public void writeResponse() throws IOException {
    writeNamedList(null, rsp.getValues());
    if(wrapperFunction!=null) {
        writer.write(')');
    }
    writer.write('\n');
  }

writeNamedList函数将map结构的返回信息写成JSON格式并返回,这里就不往下看了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值