/** Creates the action context and initializes the thread local */
  public ActionContext createActionContext(
      HttpServletRequest request, HttpServletResponse response) {
    ActionContext ctx;
    Integer counter = 1;
    Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
    if (oldCounter != null) {
      counter = oldCounter + 1;
    }

    ActionContext oldContext = ActionContext.getContext();
    if (oldContext != null) {
      // detected existing context, so we are probably in a forward
      ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
    } else {
      ValueStack stack =
          dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
      stack
          .getContext()
          .putAll(dispatcher.createContextMap(request, response, null, servletContext));

      // 利用ValueStack的context属性实例化ActionContext
      ctx = new ActionContext(stack.getContext());
    }
    request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
    ActionContext.setContext(ctx);
    return ctx;
  }
  /**
   *
   * <li>forceLookup 为false时,优先返回(ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY)
   * <li>forceLookup 为true时,每次都去获取ActionMapper实例 <br>
   *     <br>
   *     Finds and optionally creates an {@link ActionMapping}. if forceLookup is false, it first
   *     looks in the current request to see if one has already been found, otherwise, it creates it
   *     and stores it in the request. No mapping will be created in the case of static resource
   *     requests or unidentifiable requests for other servlets, for example.
   *
   * @param forceLookup if true, the action mapping will be looked up from the ActionMapper
   *     instance, ignoring if there is one in the request or not
   */
  public ActionMapping findActionMapping(
      HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {
    ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);
    if (mapping == null || forceLookup) {
      try {
        // ActionMapper默认实例是{ @link org.apache.struts2.dispatcher.mapper.DefaultActionMapper}
        mapping =
            dispatcher
                .getContainer()
                .getInstance(ActionMapper.class)
                .getMapping(request, dispatcher.getConfigurationManager());
        if (mapping != null) {
          // 设置mapping到request属性,
          request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
        }
      } catch (Exception ex) {
        dispatcher.sendError(
            request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
      }
    }

    return mapping;
  }