SpringMVC源码解析(下)

4.请求-处理链映射(HandlerMapping)
   HandlerMapping定义了请求与处理链之间的映射的策略,见如下接口。

   public interface HandlerMapping {
    String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

主要的继承类和继承结构如下

   其中
*AbstractHandlerMapping:定义了HandlerMapping实现的最基础的部分内容,包括拦截器列表和默认处理对象
*AbstractUrlHandlerMapping:在AbstractHandlerMapping的基础上,定义了从URL到处理对象的映射关系管理,其主要处理过程如下
   getHandlerInternal:

    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
            logger.debug("Looking up handler for [" + lookupPath + "]");
        }
        Object handler = lookupHandler(lookupPath, request);
        if (handler == null) {
            // We need to care for the default handler directly, since we need to
            // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
            Object rawHandler = null;
            if ("/".equals(lookupPath)) {
                rawHandler = getRootHandler();
            }
            if (rawHandler == null) {
                rawHandler = getDefaultHandler();
            }
            if (rawHandler != null) {
                validateHandler(rawHandler, request);
                handler = buildPathExposingHandler(rawHandler, lookupPath);
            }
        }
        return handler;
    }

lookupHandler:

    protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
        // Direct match?
        Object handler = this.handlerMap.get(urlPath);
        if (handler != null) {
            validateHandler(handler, request);
            return buildPathExposingHandler(handler, urlPath);
        }
        // Pattern match?
        String bestPathMatch = null;
        for (Iterator it = this.handlerMap.keySet().iterator(); it.hasNext();) {
            String registeredPath = (String) it.next();
            if (getPathMatcher().match(registeredPath, urlPath) &&
                    (bestPathMatch == null || bestPathMatch.length() < registeredPath.length())) {
                bestPathMatch = registeredPath;
            }
        }
        if (bestPathMatch != null) {
            handler = this.handlerMap.get(bestPathMatch);
            validateHandler(handler, request);
            String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPathMatch, urlPath);
            return buildPathExposingHandler(handler, pathWithinMapping);
        }
        // No handler found...
        return null;
    }

另外,其定义了Handler的注册方法registerHandler

*AbstractDetectingUrlHandlerMapping:AbstractDetectingUrlHandlerMapping 通过继承ApplicationObjectSupport实现了ApplicationContextAware接口,在初始化完成之后自动通过 ApplicationObjectSupport.setApplicationContext-->AbstractDetectingUrlHandlerMapping.initApplicationContext-->AbstractDetectingUrlHandlerMapping.detectHandlers 调用detectHandlers函数,该函数将注册到ApplicationContext的所有Bean对象逐一检查,由其子类实现的 determineUrlsForHandler判断每个Bean对象对应的URL,并将URL与Bean的关系通过 AbstractUrlHandlerMapping.registerHandler注册

    protected void detectHandlers() throws BeansException {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
        }
        String[] beanNames = (this.detectHandlersInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));

        // Take any bean name or alias that begins with a slash.
        for (int i = 0; i < beanNames.length; i++) {
            String beanName = beanNames[i];
            String[] urls = determineUrlsForHandler(beanName);
            if (!ObjectUtils.isEmpty(urls)) {
                // URL paths found: Let‘s consider it a handler.
                registerHandler(urls, beanName);
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Rejected bean name ‘" + beanNames[i] + "‘: no URL paths identified");
                }
            }
        }
    }

*BeanNameUrlHandlerMapping:非常简单,其实现determineUrlsForHandler函数,如果一个Bean以“/”开头,则认为是一个处理器类,并且以bean的名字作为映射的url,处理过程如下

    protected String[] determineUrlsForHandler(String beanName) {
        List urls = new ArrayList();
        if (beanName.startsWith("/")) {
            urls.add(beanName);
        }
        String[] aliases = getApplicationContext().getAliases(beanName);
        for (int j = 0; j < aliases.length; j++) {
            if (aliases[j].startsWith("/")) {
                urls.add(aliases[j]);
            }
        }
        return StringUtils.toStringArray(urls);
    }

*DefaultAnnotationHandlerMapping:实现determineUrlsForHandler函数,检查每个Bean对象的 类或者方法有没有RequestMapping这个Annotation,如果有,则将相应配置的URL作为该Bean对应处理的URL,处理过程如下

protected String[] determineUrlsForHandler(String beanName) {
        ApplicationContext context = getApplicationContext();
        Class<?> handlerType = context.getType(beanName);
        RequestMapping mapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);

        if (mapping == null && context instanceof ConfigurableApplicationContext &&
                context.containsBeanDefinition(beanName)) {
            ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;
            BeanDefinition bd = cac.getBeanFactory().getMergedBeanDefinition(beanName);
            if (bd instanceof AbstractBeanDefinition) {
                AbstractBeanDefinition abd = (AbstractBeanDefinition) bd;
                if (abd.hasBeanClass()) {
                    Class<?> beanClass = abd.getBeanClass();
                    mapping = AnnotationUtils.findAnnotation(beanClass, RequestMapping.class);
                }
            }
        }

        if (mapping != null) {
            // @RequestMapping found at type level
            this.cachedMappings.put(handlerType, mapping);
            Set<String> urls = new LinkedHashSet<String>();
            String[] paths = mapping.value();
            if (paths.length > 0) {
                // @RequestMapping specifies paths at type level
                for (String path : paths) {
                    addUrlsForPath(urls, path);
                }
                return StringUtils.toStringArray(urls);
            }
            else {
                // actual paths specified by @RequestMapping at method level
                return determineUrlsForHandlerMethods(handlerType);
            }
        }
        else if (AnnotationUtils.findAnnotation(handlerType, Controller.class) != null) {
            // @RequestMapping to be introspected at method level
            return determineUrlsForHandlerMethods(handlerType);
        }
        else {
            return null;
        }
    }

5.处理器适配器(HandlerAdapter)
   HandlerAdapter定义了处理类如何处理请求的策略,见如下接口

   public interface HandlerAdapter {
    boolean supports(Object handler);
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    long getLastModified(HttpServletRequest request, Object handler);
}

通过实现特定的策略,可以灵活地将任意对象转换成请求处理对象,主要实现包括:

1)SimpleControllerHandlerAdapter/HttpRequestHandlerAdapter/SimpleServletHandlerAdapter/ThrowawayController
   非常简单,面向实现实现了特定接口的处理类的情形,仅仅做一个代理执行处理,看一下其中SimpleControllerHandlerAdapter的代码如下,其特定处理实现了Controller接口的处理类

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return ((Controller) handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }

}

2)AnnotationMethodHandlerAdapter
   通过配置特定的Annotation,定义了该如何注入参数、调用哪个方法、对返回参数如何处理,主要过程如下(AnnotationMethodHandlerAdapter.invokeHandlerMethod)

try {
            ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
            Method handlerMethod = methodResolver.resolveHandlerMethod(request);
            ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
            ExtendedModelMap implicitModel = new ExtendedModelMap();

            Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
            ModelAndView mav = methodInvoker.getModelAndView(handlerMethod, result, implicitModel, webRequest);
            methodInvoker.updateSessionAttributes(
                    handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
            return mav;
        }
        catch (NoSuchRequestHandlingMethodException ex) {
            return handleNoSuchRequestHandlingMethod(ex, request, response);
        }

*ServletHandlerMethodResolver(AnnotationMethodHandlerAdapter内部类):该类通过请求URL、请求Method和处理类的RequestMapping定义,最终确定该使用处理类的哪个方法来处理请求
*ServletHandlerMethodInvoker(AnnotationMethodHandlerAdapter内部类):检查处理类相应处
理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView
6.视图策略(ViewResolver)
  ViewResolver定义了如何确定处理视图的View对象的策略,见如下接口

public interface ViewResolver {
    View resolveViewName(String viewName, Locale locale) throws Exception;
}
时间: 2024-08-13 00:54:10

SpringMVC源码解析(下)的相关文章

SpringMVC源码解析- HandlerAdapter - ModelFactory

ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1. 初始化model 1.1 解析类上使用的sessionAttributres,将获取参数合并到mavContainer中 1.2 执行注解了@ModelAttribute的方法,并将结果同步到Model 参数名的生成规则:@ModelAttribute中定义的value > 方法的返回类型决定(

SpringMVC源码解析- HandlerAdapter初始化

HandlerAdapter初始化时,主要是进行注解解析器初始化注册;返回值处理类初始化;全局注解@ControllerAdvice内容读取并缓存. 目录: 注解解析器初始化注册:@ModelAttribute(往model中添加属性) 注解解析器初始化注册:@InitBinder(用于注册校验器,参数编辑器等) 返回值处理returnValueHandlers初始化 全局的@ControllerAdvice注解使用类的@ModelAttribute 和 @InitBinder信息读取并缓存 注

springmvc源码解析-初始化

1.      概述 对于Web开发者,MVC模型是大家再熟悉不过的了,SpringMVC中,满足条件的请求进入到负责请求分发的DispatcherServlet,DispatcherServlet根据请求url到控制器的映射(HandlerMapping中保存),HandlerMapping最终返回HandlerExecutionChain,其中包含了具体的处理对象handler(也即我们编程时写的controller)以及一系列的拦截器interceptors,此时DispatcherSer

SpringMVC源码解析

1. SpringMVC重要组件 1. DispatcherServlet SpringMVC的中央Servlet,所有请求的入口,重写了doService()方法.核心方法:doService().doDispatch(). 2. HandlerMapping 处理器映射,负责根据HttpServletRequest找到对应的Handler,这里返回Handler的辅助类HandlerExecutionChain. public interface HandlerMapping { @Null

SpringMVC源码解析 - HandlerMethod

HandlerMethod及子类主要用于封装方法调用相关信息,子类还提供调用,参数准备和返回值处理的职责. 分析下各个类的职责吧(顺便做分析目录): HandlerMethod 封装方法定义相关的信息,如类,方法,参数等. 使用场景:HandlerMapping时会使用 InvocableHandlerMethod 添加参数准备,方法调用功能 使用场景:执行使用@ModelAttribute注解会使用 ServletInvocableHandlerMethod 添加返回值处理职责,Respons

SpringMVC源码解析-DispatcherServlet启动流程和初始化

在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从DispatcherServlet入手,从名字来看,它是一个Servlet.它的定义如下: public class DispatcherServlet extends FrameworkServlet { 它是继承FrameworkServlet,来看一下整个的继承关系. 从继承关系来看,Dispatc

SpringMVC源码解析 - HandlerAdater - ModelAndViewContainer上下文容器

HandlerAdapter在处理请求时上下文数据的传递工作是由ModelAndViewContainer负责的. 源码注释是这样描述的: Records model and view related decisions made by HandlerMethodArgumentResolvers and HandlerMethodReturnValueHandlers during the course of invocation of a controller method. 翻译下: 记录

SpringMVC源码解析 - HandlerAdapter - @SessionAttributes注解处理

使用SpringMVC开发时,可以使用@SessionAttributes注解缓存信息.这样业务开发时,就不需要一次次手动操作session保存,读数据. 1 @Controller 2 @RequestMapping("telephones") 3 @SessionAttributes(value={"name","degree"},types={Double.class}) 4 public class AttributeController

SpringMVC源码解析(上)

原文:http://ayufox.iteye.com/blog/393226 1.从DispatcherServlet开始     与很多使用广泛的MVC框架一样,SpringMVC使用的是FrontController模式,所有的设计都围绕DispatcherServlet为中心来展开的.见下图,所有请求从DispatcherServlet进入,DispatcherServlet根据配置好的映射策略确定处理的Controller,Controller处理完成返回ModelAndView,Dis