Discuz! Board

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2|回复: 2
打印 上一主题 下一主题

spring mvc DispatcherServlet详解

[复制链接]

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
跳转到指定楼层
楼主
发表于 2016-2-25 19:01:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
四个部分内容,详解了整个SpringMVC的请求过程。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
沙发
 楼主| 发表于 2016-2-25 19:11:28 | 只看该作者

spring mvc DispatcherServlet详解之一---处理请求深入解析

要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构:

从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServlet 就完全可以说弄清楚了spring mvc。
为了加深对spring mvc的整个工作流程的理解,本文从分析DispatcherServlet的工作过程来一窥spring mvc的整个面貌。
1. 初始化
protected void initStrategies(ApplicationContext context) {
        initMultipartResolver(context); //文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
        initLocaleResolver(context);    //本地化解析
        initThemeResolver(context);   //主题解析
        initHandlerMappings(context);   //通过HandlerMapping,将请求映射到处理器
        initHandlerAdapters(context);   //通过HandlerAdapter支持多种类型的处理器
        initHandlerExceptionResolvers(context); //如果执行过程中遇到异常将交给HandlerExceptionResolver来解析
        initRequestToViewNameTranslator(context); //直接解析请求到视图名
        initViewResolvers(context);      //通过ViewResolver解析逻辑视图名到具体视图实现
        initFlashMapManager(context);   //flash映射管理器
    }
单个resolverinitMultipartResolver,initLocaleResolver,initThemeResolver,initRequestToViewNameTranslator,initFlashMapManager 这五个初始化方法流程相同,都是使用
context.getBean(String name, Class<FlashMapManager> requiredType)的方式获取到相应的Resolver。以initMultipartResolver为例,见如下:
/**
     * Initialize the MultipartResolver used by this class.
     * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
     * no multipart handling is provided.
     */
    private void initMultipartResolver(ApplicationContext context) {
        try {
            this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
            }
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Default is no multipart resolver.
            this.multipartResolver = null;
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
                        "': no multipart request handling provided");
            }
        }

    }
多个resolver
initHandlerMappings,initHandlerAdapters,initHandlerExceptionResolvers,initViewResolvers 获取方式相同,使用:
BeanFactoryUtils.beansOfTypeIncludingAncestors(ListableBeanFactory lbf, Class<HandlerMapping> type, boolean includeNonSingletons, boolean allowEagerInit)
的方式获取到相应的Resolver。以initHandlerMappings为例,见如下:/**     * Initialize the HandlerMappings used by this class.     * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,     * we default to BeanNameUrlHandlerMapping.     */    private void initHandlerMappings(ApplicationContext context) {        this.handlerMappings = null;        if (this.detectAllHandlerMappings) {            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.            Map<String, HandlerMapping> matchingBeans =                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);            if (!matchingBeans.isEmpty()) {                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());                // We keep HandlerMappings in sorted order.                OrderComparator.sort(this.handlerMappings);            }        }        else {            try {                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);                this.handlerMappings = Collections.singletonList(hm);            }            catch (NoSuchBeanDefinitionException ex) {                // Ignore, we'll add a default HandlerMapping later.            }        }        // Ensure we have at least one HandlerMapping, by registering        // a default HandlerMapping if no other mappings are found.        if (this.handlerMappings == null) {            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);            if (logger.isDebugEnabled()) {                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");            }        }    }
那么深入看一下BeanFactoryUtils.beansOfTypeIncludingAncestors 究竟做了什么?返回指定类型和子类型的所有bean,若该bean factory 是一个继承类型的beanFactory,这个方法也会获取祖宗factory中定义的指定类型的bean。/**     * Return all beans of the given type or subtypes, also picking up beans defined in     * ancestor bean factories if the current bean factory is a HierarchicalBeanFactory.     * The returned Map will only contain beans of this type.     * <p>Does consider objects created by FactoryBeans if the "allowEagerInit" flag is set,     * which means that FactoryBeans will get initialized. If the object created by the     * FactoryBean doesn't match, the raw FactoryBean itself will be matched against the     * type. If "allowEagerInit" is not set, only raw FactoryBeans will be checked     * (which doesn't require initialization of each FactoryBean).     * <p><b>Note: Beans of the same name will take precedence at the 'lowest' factory level,     * i.e. such beans will be returned from the lowest factory that they are being found in,     * hiding corresponding beans in ancestor factories.</b> This feature allows for     * 'replacing' beans by explicitly choosing the same bean name in a child factory;     * the bean in the ancestor factory won't be visible then, not even for by-type lookups.     * @param lbf the bean factory     * @param type type of bean to match     * @param includeNonSingletons whether to include prototype or scoped beans too     * or just singletons (also applies to FactoryBeans)     * @param allowEagerInit whether to initialize <i>lazy-init singletons</i> and     * <i>objects created by FactoryBeans</i> (or by factory methods with a     * "factory-bean" reference) for the type check. Note that FactoryBeans need to be     * eagerly initialized to determine their type: So be aware that passing in "true"     * for this flag will initialize FactoryBeans and "factory-bean" references.     * @return the Map of matching bean instances, or an empty Map if none     * @throws BeansException if a bean could not be created     */    public static <T> Map<String, T> beansOfTypeIncludingAncestors(            ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)            throws BeansException {
        Assert.notNull(lbf, "ListableBeanFactory must not be null");        Map<String, T> result = new LinkedHashMap<String, T>(4);        result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));        if (lbf instanceof HierarchicalBeanFactory) {            HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;            if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {                Map<String, T> parentResult = beansOfTypeIncludingAncestors(                        (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);                for (Map.Entry<String, T> entry : parentResult.entrySet()) {                    String beanName = entry.getKey();                    if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {                        result.put(beanName, entry.getValue());                    }                }            }        }        return result;    }
2. 提供服务
     我们来看看这个servlet是如何提供服务的?
@Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
            logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                    " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
        }

        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            attributesSnapshot = new HashMap<String, Object>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {
                String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // Make framework objects available to handlers and view objects.
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

        try {
            doDispatch(request, response);
        }
        finally {
            if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                return;
            }
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
从上面我们可以看到,提供服务只要分4步:
  1. 保存现场。保存request 熟悉的快照,以便能在必要时恢复。
  2. 将框架需要的对象放入request中,以便view和handler使用。
  3. 请求分发服务.
  4. 恢复现场。
其中最重要的是请求分发服务:
/**
     * Process the actual dispatching to the handler.
     * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     * to find the first that supports the handler class.
     * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     * themselves to decide which methods are acceptable.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }

                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                try {
                    // Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }

                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
分发过程如下:
1. 判断是否设置了multipart resolver,设置的话转换为multipart request,没有的话则继续下面的步骤。
2. 根据当前request,获取hangdler。
3. 根据当前request,获取HandlerAdapter。
4. 如果支持http请求头,处理 last-modified header请求头。
5. 应用已注册interceptor的preHandle方法
6. HandlerAdapter处理请求。
7. 设置默认视图。
8. 应用已注册interceptor的postHandle方法。
9. 处理异常或者视图渲染。
小结:
   DispatherServlet整个过程的细节一章之内很难描述的面面俱到,只能分析部分流程,想了解更具体的实现需要从源代码中去寻找。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

1198

主题

2060

帖子

7058

积分

超级版主

Rank: 8Rank: 8

积分
7058
板凳
 楼主| 发表于 2016-2-25 19:30:36 | 只看该作者

spring mvc DispatcherServlet详解之二---request通过Controller获取Model...

整个spring mvc的架构如下图所示:

上篇文件讲解了DispatcherServlet通过request获取控制器Controller的过程,现在来讲解DispatcherServletDispatcherServlet的第二步:通过request从Controller获取ModelAndView。
DispatcherServlet调用Controller的过程:
DispatcherServlet.java
doService()--->doDispatch()--->handlerAdapter的handle()方法
try {// Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                }
}
最常用的实现了HandlerAdapter接口是SimpleControllerHandlerAdapter类,该类将
两个不兼容的类:DispatcherServlet 和Controller 类连接到一起。Adapter to use the plain {@link Controller} workflow interface with  the generic {@link org.springframework.web.servlet.DispatcherServlet}.  Supports handlers that implement the {@link LastModified} interface.   <p>This is an SPI class, not used directly by application code.类之间的转换代码如下所示,调用了Controller类的handleRequest()方法来处理请求:@Override    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)            throws Exception {        return ((Controller) handler).handleRequest(request, response);    }重量级人物控制器Controller开始闪亮登场,Controller是一个基本的接口,它接受request和response,从这点上来说,它有点像servlet,但不同之处在于它在mvc模式流程中起作用,它和struts中的Action作用类似。继承该接口的控制器或者类应该保证是线程安全的,可复用的,能够在一个应用生命周期中处理大量的request。为了使Controller的配置更便捷,通常使用javaBeans来继承Controller。Controller的handleRequest()方法处理请求,并返回ModelAndView给DispatcherServlet去渲染render。/** * Base Controller interface, representing a component that receives * {@code HttpServletRequest} and {@code HttpServletResponse} * instances just like a {@code HttpServlet} but is able to * participate in an MVC workflow. Controllers are comparable to the * notion of a Struts {@code Action}. * * <p>Any implementation of the Controller interface should be a * <i>reusable, thread-safe</i> class, capable of handling multiple * HTTP requests throughout the lifecycle of an application. To be able to * configure a Controller easily, Controller implementations are encouraged * to be (and usually are) JavaBeans. * </p> * * <p><b><a name="workflow">Workflow</a></b></p> * * <p> * After a <cde>DispatcherServlet</code> has received a request and has * done its work to resolve locales, themes and suchlike, it then tries * to resolve a Controller, using a * {@link org.springframework.web.servlet.HandlerMapping HandlerMapping}. * When a Controller has been found to handle the request, the * {@link #handleRequest(HttpServletRequest, HttpServletResponse) handleRequest} * method of the located Controller will be invoked; the located Controller * is then responsible for handling the actual request and - if applicable - * returning an appropriate * {@link org.springframework.web.servlet.ModelAndView ModelAndView}. * So actually, this method is the main entrypoint for the * {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet} * which delegates requests to controllers.</p> * * <p>So basically any <i>direct</i> implementation of the Controller interface * just handles HttpServletRequests and should return a ModelAndView, to be further * interpreted by the DispatcherServlet. Any additional functionality such as * optional validation, form handling, etc should be obtained through extending * one of the abstract controller classes mentioned above.</p> * * <p><b>Notes on design and testing</b></p> * * <p>The Controller interface is explicitly designed to operate on HttpServletRequest * and HttpServletResponse objects, just like an HttpServlet. It does not aim to * decouple itself from the Servlet API, in contrast to, for example, WebWork, JSF or Tapestry. * Instead, the full power of the Servlet API is available, allowing Controllers to be * general-purpose: a Controller is able to not only handle web user interface * requests but also to process remoting protocols or to generate reports on demand.</p> * * <p>Controllers can easily be tested by passing in mock objects for the * HttpServletRequest and HttpServletResponse objects as parameters to the * {@link #handleRequest(HttpServletRequest, HttpServletResponse) handleRequest} * method. As a convenience, Spring ships with a set of Servlet API mocks * that are suitable for testing any kind of web components, but are particularly * suitable for testing Spring web controllers. In contrast to a Struts Action, * there is no need to mock the ActionServlet or any other infrastructure; * HttpServletRequest and HttpServletResponse are sufficient.</p> * * <p>If Controllers need to be aware of specific environment references, they can * choose to implement specific awareness interfaces, just like any other bean in a * Spring (web) application context can do, for example:</p> * <ul> * <li>{@code org.springframework.context.ApplicationContextAware}</li> * <li>{@code org.springframework.context.ResourceLoaderAware}</li> * <li>{@code org.springframework.web.context.ServletContextAware}</li> * </ul> * * <p>Such environment references can easily be passed in testing environments, * through the corresponding setters defined in the respective awareness interfaces. * In general, it is recommended to keep the dependencies as minimal as possible: * for example, if all you need is resource loading, implement ResourceLoaderAware only. * Alternatively, derive from the WebApplicationObjectSupport base class, which gives * you all those references through convenient accessors - but requires an * ApplicationContext reference on initialization. * * <p>Controllers can optionally implement the {@link LastModified} interface.
*/
Controller接口的抽象实现类为:AbstractController,它通过互斥锁(mutex)来保证线程安全。
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)            throws Exception {        // Delegate to WebContentGenerator for checking and preparing.        checkAndPrepare(request, response, this instanceof LastModified);        // Execute handleRequestInternal in synchronized block if required.        if (this.synchronizeOnSession) {            HttpSession session = request.getSession(false);            if (session != null) {                Object mutex = WebUtils.getSessionMutex(session);                synchronized (mutex) {                    return handleRequestInternal(request, response);                }            }        }        return handleRequestInternal(request, response);    }}handleRequestInternal()为抽象方法,留待具体实现类来实现。它的直接子类有:AbstractUrlViewController, MultiActionController, ParameterizableViewController, ServletForwardingController, ServletWrappingControlle
在web.xml中有时候定义节点<welcome-list>index.html</welcome-list>等,这种简单的请,Controller是如何实现的呢?我们来看看UrlFilenameViewController,它是Controller的一个间接实现,实现了AbstractUrlViewController。它把url的虚拟路径转换成一个view的名字,然后返回这个view。
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);        String viewName = getViewNameForRequest(request);        if (logger.isDebugEnabled()) {            logger.debug("Returning view name '" + viewName + "' for lookup path [" + lookupPath + "]");        }        return new ModelAndView(viewName, RequestContextUtils.getInputFlashMap(request));}
复杂Controller实现
一个可以处理多种请求类型的Controller实现:MultiActionController。它类似于struts中的DispatcherAction,但更灵活,而且支持代理。
/** * {@link org.springframework.web.servlet.mvc.Controller Controller} * implementation that allows multiple request types to be handled by the same * class. Subclasses of this class can handle several different types of * request with methods of the form * * <pre class="code">public (ModelAndView | Map | String | void) actionName(HttpServletRequest request, HttpServletResponse response, [,HttpSession] [,AnyObject]);</pre> * * A Map return value indicates a model that is supposed to be passed to a default view * (determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}). * A String return value indicates the name of a view to be rendered without a specific model. * * <p>May take a third parameter (of type {@link HttpSession}) in which an * existing session will be required, or a third parameter of an arbitrary * class that gets treated as the command (that is, an instance of the class * gets created, and request parameters get bound to it) * * <p>These methods can throw any kind of exception, but should only let * propagate those that they consider fatal, or which their class or superclass * is prepared to catch by implementing an exception handler. * * <p>When returning just a {@link Map} instance view name translation will be * used to generate the view name. The configured * {@link org.springframework.web.servlet.RequestToViewNameTranslator} will be * used to determine the view name. * * <p>When returning {@code void} a return value of {@code null} is * assumed meaning that the handler method is responsible for writing the * response directly to the supplied {@link HttpServletResponse}. * * <p>This model allows for rapid coding, but loses the advantage of * compile-time checking. It is similar to a Struts {@code DispatchAction}, * but more sophisticated. Also supports delegation to another object. * * <p>An implementation of the {@link MethodNameResolver} interface defined in * this package should return a method name for a given request, based on any * aspect of the request, such as its URL or an "action" parameter. The actual * strategy can be configured via the "methodNameResolver" bean property, for * each {@code MultiActionController}. * * <p>The default {@code MethodNameResolver} is * {@link InternalPathMethodNameResolver}; further included strategies are * {@link PropertiesMethodNameResolver} and {@link ParameterMethodNameResolver}. * * <p>Subclasses can implement custom exception handler methods with names such * as: * * <pre class="code">public ModelAndView anyMeaningfulName(HttpServletRequest request, HttpServletResponse response, ExceptionClass exception);</pre> * * The third parameter can be any subclass or {@link Exception} or * {@link RuntimeException}. * * <p>There can also be an optional {@code xxxLastModified} method for * handlers, of signature: * * <pre class="code">public long anyMeaningfulNameLastModified(HttpServletRequest request)</pre> * * If such a method is present, it will be invoked. Default return from * {@code getLastModified} is -1, meaning that the content must always be * regenerated. * * <p><b>Note that all handler methods need to be public and that * method overloading is <i>not</i> allowed.</b> * * <p>See also the description of the workflow performed by * {@link AbstractController the superclass} (in that section of the class * level Javadoc entitled 'workflow'). * * <p><b>Note:</b> For maximum data binding flexibility, consider direct usage of a * {@link ServletRequestDataBinder} in your controller method, instead of relying * on a declared command argument. This allows for full control over the entire * binder setup and usage, including the invocation of {@link Validator Validators} * and the subsequent evaluation of binding/validation errors.*/
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)            throws Exception {        try {            String methodName = this.methodNameResolver.getHandlerMethodName(request);            return invokeNamedMethod(methodName, request, response);        }        catch (NoSuchRequestHandlingMethodException ex) {            return handleNoSuchRequestHandlingMethod(ex, request, response);        }    }触发执行方法:
protected final ModelAndView invokeNamedMethod(            String methodName, HttpServletRequest request, HttpServletResponse response) throws Exception {        Method method = this.handlerMethodMap.get(methodName);        if (method == null) {            throw new NoSuchRequestHandlingMethodException(methodName, getClass());        }        try {            Class<?>[] paramTypes = method.getParameterTypes();            List<Object> params = new ArrayList<Object>(4);            params.add(request);            params.add(response);            if (paramTypes.length >= 3 && paramTypes[2].equals(HttpSession.class)) {                HttpSession session = request.getSession(false);                if (session == null) {                    throw new HttpSessionRequiredException(                            "Pre-existing session required for handler method '" + methodName + "'");                }                params.add(session);            }            // If last parameter isn't of HttpSession type, it's a command.            if (paramTypes.length >= 3 &&                    !paramTypes[paramTypes.length - 1].equals(HttpSession.class)) {                Object command = newCommandObject(paramTypes[paramTypes.length - 1]);                params.add(command);                bind(request, command);            }            Object returnValue = method.invoke(this.delegate, params.toArray(new Object[params.size()]));            return massageReturnValueIfNecessary(returnValue);        }        catch (InvocationTargetException ex) {            // The handler method threw an exception.            return handleException(request, response, ex.getTargetException());        }        catch (Exception ex) {            // The binding process threw an exception.            return handleException(request, response, ex);        }

处理返回结果,要么返回null要么返回ModelAndView实例。当返回一个Map类型时,ModelAndView实例包装的Map类型。    /**     * Processes the return value of a handler method to ensure that it either returns     * {@code null} or an instance of {@link ModelAndView}. When returning a {@link Map},     * the {@link Map} instance is wrapped in a new {@link ModelAndView} instance.     */    @SuppressWarnings("unchecked")    private ModelAndView massageReturnValueIfNecessary(Object returnValue) {        if (returnValue instanceof ModelAndView) {            return (ModelAndView) returnValue;        }        else if (returnValue instanceof Map) {            return new ModelAndView().addAllObjects((Map<String, ?>) returnValue);        }        else if (returnValue instanceof String) {            return new ModelAndView((String) returnValue);        }        else {            // Either returned null or was 'void' return.            // We'll assume that the handle method already wrote the response.            return null;        }    }
小结:
   DispatcherServlet接受一个请求,然后解析完locales, themes等后,通过HadlerMapping解析控制器Controller去处理请求。
   找到Controller后,出发当前controller的handleRequest()方法,此controller负责真正处理请求,然后一个ModelAndView实例。
  DispatcherServlet 代理此Controller,接收返回结果,然后进行渲染。











本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Comsenz Inc.

GMT+8, 2025-12-15 04:19 , Processed in 0.019421 second(s), 7 queries , Apc On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表