zoukankan      html  css  js  c++  java
  • springmvc 的请求处理过程(精编)

    springmvc 的请求处理过程(精编)

     

     

    1. DispacherServlet 前端控制器接受发送过来的请求,交给HandlerMapping 处理映射器,

    2. HandlerMapping 处理映射器, 根据请求找到相应的HandlerAdapter 处理适配器(处理适配器就是那些拦截器活着吧Controller)

    3. HandlerAdapter处理器适配器,处理一些功能请求, 返回一个ModleAndView 对象,包括模型数据、逻辑视图名。

    ViewResolver视图解析器 ,先根据ModleAndView 中设置的view 解析具体视图

    5. 然后将Modle模型中得数据渲染到View中。

    这些过程都是以DispatchServlet 为中轴线进行的。

     

    首先说说:HandlerMapping 视图解析器的接口

    作用是根据当前请求的找到对应的Handler 并将Handler(执行程序) 与一对HandlerInterceptor(拦截器)封装到HandlerExecutionChain 对象中。在HandlerMapping接口的内部只有一个方法,如下

    • HandlerExecutionChain getHandler(HttpServletRequest request);

    HandlerMapping 是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler,而 HandlerMapping 具体有哪些实现类下面就会详细分析。

     

     HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 HttpRequestHandler、Controller 或 Servlet),它们又统一继承于AbstractHandlerMapping

     

     

    先来看一下 AbstractHandlerMapping,它实现了 HandlerMapping 接口中的 getHandler() 方法,源码如下所示:

    @Override

    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

    // 根据请求获取执行程序,具体的获取方式由子类决定,getHandlerInternal() 是抽象方法

    Object handler = getHandlerInternal(request);

    if (handler == null) {

    handler = getDefaultHandler();

    }

    if (handler == null) {

    return null;

    }

    // Bean name or resolved handler?

    if (handler instanceof String) {

    String handlerName = (String) handler;

    handler = getApplicationContext().getBean(handlerName);

    }

    // 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中

    return getHandlerExecutionChain(handler, request);

    }

    //  Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中

     

    可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。下面就来一看下 AbstractHandlerMapping 的两个分支子类。

     

    2):AbstractHandlerMethodMapping

    AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如Method),这样一个 Controller 就可以处理多个请求了,源码如下所示:

     

    @Override

    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {

    // 根据当前请求获取“查找路径” 从 HttpServletRequest中获取请求的路径。

    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

    // 获取当前请求最佳匹配的处理方法(即Controller类的方法中)(获取请求中的方法)

    HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

    return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

    }

     

     

     

    下面的是 lookupHandlerMethod(lookupPath, request); 的方法体:

    @Nullable

    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {

    List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();

    //根据请的路径找到 直接访问的路径。

    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);

    if (directPathMatches != null) {

    this.addMatchingMappings(directPathMatches, matches, request);

    }

     

    if (matches.isEmpty()) {

    this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);

    }

     

    if (!matches.isEmpty()) {

    Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));

    Collections.sort(matches, comparator);

    if (this.logger.isTraceEnabled()) {

    this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);

    }

     

    AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);

    if (matches.size() > 1) {

    if (CorsUtils.isPreFlightRequest(request)) {

    return PREFLIGHT_AMBIGUOUS_MATCH;

    }

     

    AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);

    if (comparator.compare(bestMatch, secondBestMatch) == 0) {

    Method m1 = bestMatch.handlerMethod.getMethod();

    Method m2 = secondBestMatch.handlerMethod.getMethod();

    throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");

    }

    }

     

    this.handleMatch(bestMatch.mapping, lookupPath, request);

    return bestMatch.handlerMethod;

    else {

    return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);

    }

    }

    上述代码中 lookupHandlerMethod() 方法主要工作是在 Map<T, HandlerMethod> handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了 @RequestMapping 注解中的信息。那 HandlerMethod 是怎么创建的(即怎么把 Controller 的方法变成了它),

    即: mapping 与handlerMethod(处理方法的)关系;

    继续看一下源码找到 initHandlerMethods() 方法,这个方法是在这个类创建后调用的,如下所示是它的源码:

     

    protected void initHandlerMethods() {

    // 从容器中获取所有 Bean 的名称,detectHandlerMethodsInAncestorContexts 默认false,不从父容器中查找

    //即默认只查找 SpringMVC 的 IOC 容器,不查找它的父容器 Spring 的 IOC 容器

    String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?

    BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :

    getApplicationContext().getBeanNamesForType(Object.class));

    for (String beanName : beanNames) {

    // 这里的 isHandler()方法由子类实现,判断是否拥有 @Controller 注解或 @RequestMapping 注解

    if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){

    // 利用反射得到 Bean 中的 Method 并包装成 HandlerMethod,然后放入 Map 中

    detectHandlerMethods(beanName);

    }

    }

    handlerMethodsInitialized(getHandlerMethods());

    }

    看完上述代码后,可以知道是在 detectHandlerMethods() 方法中将 Bean 的方法转换为 HandlerMethod 对象,具体实现如下

     

    protected void detectHandlerMethods(final Object handler) {

    // 获取这个 Bean 的 Class 对象

    Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());

    // 避免重复调用 getMappingForMethod(),getMappingForMethod() 将重新构建 RequestMappingInfo 实例

    final Map<Method, T> mappings = new IdentityHashMap<Method, T>();

    // 获取被代理前的原始类型

    final Class<?> userType = ClassUtils.getUserClass(handlerType);

    // 获取 Method

    Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {

    @Override

    public boolean matches(Method method) {

    // 根据 Method 和它的 @RequestMapping 注解,创建 RequestMappingInfo 对象。

    // 这里的 T 就是 RequestMappingInfo,它封装了 @RequestMapping 信息

    T mapping = getMappingForMethod(method, userType);

    if (mapping != null) {

    mappings.put(method, mapping);

    return true;

    } else {

    return false;

    }

    }

    });

    for (Method method : methods) {

    // 注册 Method 和它的映射,RequestMappingInfo 储存着映射信息

    registerHandlerMethod(handler, method, mappings.get(method));

    }

    }

     

    最后在 registerHandlerMethod() 方法中,将 RequestMappingInfo 作为 key,把 Method 包装成HandlerMethod 作为 value 添加到了 Map<T, HandlerMethod> handlerMethods 中。

     

    protected void registerHandlerMethod(Object handler, Method method, T mapping) {

    HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);

    HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);

    if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {

    throw new IllegalStateException("");

    }

    this.handlerMethods.put(mapping, newHandlerMethod);

    Set<String> patterns = getMappingPathPatterns(mapping);

    for (String pattern : patterns) {

    if (!getPathMatcher().isPattern(pattern)) {

    this.urlMap.add(pattern, mapping);

    }

    }

    }

     

     

    接下来我们接着看看:HandlerAdapter

    根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。HandlerAdapter 接口中的方法如下:

     

    HandlerAdapter的接口的方法:

    public interface HandlerAdapter {

    boolean supports(Object var1);

    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

     

    long getLastModified(HttpServletRequest var1, Object var2);

    }

     

    该接口的具体的实现类有:

    HttpRequestHandlerAdapterSimpleControllerHandlerAdapterAnnotationMethodHandlerAdapter,这个三个类是具体实现HandlerAdapter这个接口的三个类;

    1 RequestMappingHandlerAdapter

    从上面的文章中可以知道,利用 RequestMappingHandlerMapping 获取的 Handler 是 HadnlerMethod 类型,它代表 Controller 里要执行的方法,而 RequestMappingHandlerAdapter 可以执行 HadnlerMethod 对象。

    RequestMappingHandlerAdapter 的 handle()方法是在它的父类 AbstractHandlerMethodAdapter 类中实现的,源码如下所示

     

    @Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }

     

    handleInternal() 方法是由 RequestMappingHandlerAdapter 自己来实现的,源码如下所示

     

    @Override

    protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    // 是否通过 @SessionAttributes 注释声明了 session 属性。

    if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {

    checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);

    } else {

    checkAndPrepare(request, response, true);

    }

    // 是否需要在 synchronize 块中执行

    if (this.synchronizeOnSession) {

    HttpSession session = request.getSession(false);

    if (session != null) {

    Object mutex = WebUtils.getSessionMutex(session);

    synchronized (mutex) {

    // 执行 HandlerMethod

    return invokeHandleMethod(request, response, handlerMethod);

    }

    }

    }

    // 执行 HandlerMethod,得到 ModelAndView

    return invokeHandleMethod(request, response, handlerMethod);

    }

     

    继续再来看一下如何得到 ModelAndViewinvokeHandlerMethod() 方法如下

     

    private ModelAndView invokeHandleMethod(HttpServletRequest request,

    HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    //

    ServletWebRequest webRequest = new ServletWebRequest(request, response);

    // 数据绑定

    WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);

    ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

    // 绑定参数,执行方法

    ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

    // 创建模型和视图容器

    ModelAndViewContainer mavContainer = new ModelAndViewContainer();

    // 设置FlasgMap中的值

    mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));

    // 初始化模型

    modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);

    mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

     

    AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);

    asyncWebRequest.setTimeout(this.asyncRequestTimeout);

     

    final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    asyncManager.setTaskExecutor(this.taskExecutor);

    asyncManager.setAsyncWebRequest(asyncWebRequest);

    asyncManager.registerCallableInterceptors(this.callableInterceptors);

    asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

    if (asyncManager.hasConcurrentResult()) {

    Object result = asyncManager.getConcurrentResult();

    mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];

    asyncManager.clearConcurrentResult();

    requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);

    }

    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

    if (asyncManager.isConcurrentHandlingStarted()) {

    return null;

    }

    return getModelAndView(mavContainer, modelFactory, webRequest);

    }

     

     

    2 HttpRequestHandlerAdapter

    HttpRequestHandlerAdapter 可以执行 HttpRequestHandler 类型的 Handler,源码如下

    @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; }

     

    3 SimpleControllerHandlerAdapter

    SimpleControllerHandlerAdapter 可以执行 Controller 类型的 Handler,源码如下

    @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }

     

    4 SimpleServletHandlerAdapter 

    SimpleServletHandlerAdapter 可以执行 Servlet 类型的 Handler,源码如下

    @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }

     

    ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex); 

     

  • 相关阅读:
    hdu 1254 推箱子(双重bfs)
    hdu 1495 非常可乐 (广搜)
    [leetcode-687-Longest Univalue Path]
    [leetcode-686-Repeated String Match]
    POJ 2287 田忌赛马 贪心算法
    [leetcode-304-Range Sum Query 2D
    [leetcode-682-Baseball Game]
    [leetcode-299-Bulls and Cows]
    [leetcode-319-Bulb Switcher]
    [leetcode-680-Valid Palindrome II]
  • 原文地址:https://www.cnblogs.com/wangdong811/p/10300247.html
Copyright © 2011-2022 走看看