spring mvc DispatcherServlet详解之---获取控制器

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

现在来讲解DispatcherServletDispatcherServlet的第一步:获取控制器。

HandlerMapping

HandlerMappings 定义request和handler之间的映射。它的官方文档这样描述:
Interface HandlerMapping

All Known Implementing Classes:
AbstractControllerUrlHandlerMapping, AbstractDetectingUrlHandlerMapping, AbstractHandlerMapping, AbstractHandlerMethodMapping, AbstractUrlHandlerMapping, BeanNameUrlHandlerMapping, ControllerBeanNameHandlerMapping, ControllerClassNameHandlerMapping, DefaultAnnotationHandlerMapping, RequestMappingHandlerMapping, RequestMappingInfoHandlerMapping, SimpleUrlHandlerMapping
Functional Interface:
This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. 

--------------------------------------------------------------------------------

public interface HandlerMappingInterface to be implemented by objects that define a mapping between requests and handler objects.
This class can be implemented by application developers, although this is not necessary, as BeanNameUrlHandlerMapping and SimpleUrlHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. 

HandlerMapping implementations can support mapped interceptors but do not have to. A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor‘s preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true. 

The ability to parameterize this mapping is a powerful and unusual capability of this MVC framework. For example, it is possible to write a custom mapping based on session state, cookie state or many other variables. No other MVC framework seems to be equally flexible. 

Note: Implementations can implement the Ordered interface to be able to specify a sorting order and thus a priority for getting applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.

1. 初始化HandlerMapping

    /**
     * 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");
            }
        }
    }

2.获取HandlerExecutionChain。

HandlerExecutionChain包含了handler对象和任意多hangdler拦截器。

    /**
     * Return the HandlerExecutionChain for this request.
     * <p>Tries all handler mappings in order.
     * @param request current HTTP request
     * @return the HandlerExecutionChain, or {@code null} if no handler could be found
     */
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name ‘" + getServletName() + "‘");
            }
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }
/**
     * Look up a handler for the given request, falling back to the default
     * handler if no specific one is found.
     * @param request current HTTP request
     * @return the corresponding handler instance, or the default handler
     * @see #getHandlerInternal
     */
    @Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        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);
        }
        return getHandlerExecutionChain(handler, request);
    }
    /**
     * Look up a handler for the URL path of the given request.
     * @param request current HTTP request
     * @return the handler instance, or {@code null} if none found
     */
    @Override
    protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        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) {
                // Bean name or resolved handler?
                if (rawHandler instanceof String) {
                    String handlerName = (String) rawHandler;
                    rawHandler = getApplicationContext().getBean(handlerName);
                }
                validateHandler(rawHandler, request);
                handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
            }
        }
        if (handler != null && logger.isDebugEnabled()) {
            logger.debug("Mapping [" + lookupPath + "] to " + handler);
        }
        else if (handler == null && logger.isTraceEnabled()) {
            logger.trace("No handler mapping found for [" + lookupPath + "]");
        }
        return handler;
    }
    /**
     * Build a {@link HandlerExecutionChain} for the given handler, including
     * applicable interceptors.
     * <p>The default implementation builds a standard {@link HandlerExecutionChain}
     * with the given handler, the handler mapping‘s common interceptors, and any
     * {@link MappedInterceptor}s matching to the current request URL. Subclasses
     * may override this in order to extend/rearrange the list of interceptors.
     * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
     * pre-built {@link HandlerExecutionChain}. This method should handle those
     * two cases explicitly, either building a new {@link HandlerExecutionChain}
     * or extending the existing chain.
     * <p>For simply adding an interceptor in a custom subclass, consider calling
     * {@code super.getHandlerExecutionChain(handler, request)} and invoking
     * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
     * @param handler the resolved handler instance (never {@code null})
     * @param request current HTTP request
     * @return the HandlerExecutionChain (never {@code null})
     * @see #getAdaptedInterceptors()
     */
    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
        HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
        chain.addInterceptors(getAdaptedInterceptors());

        String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
        for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }

        return chain;
    }

 HandlerAdapter

让我们先复习一下适配器模式吧:

An adapter helps two incompatible interfaces to work together. This is the real world definition for an adapter. The adapter design pattern is used when you want two different classes with incompatible interfaces to work together. Interfaces may be incompatible but the inner functionality should suit the need. The Adapter pattern allows otherwise incompatible classes to work together by converting the interface of one class into an interface expected by the clients.

适配器帮助两个不兼容接口连接到一起进行工作,这是真实世界对适配器的定义。在设计模式中适配器用来连接实现了不兼容接口的两个类。接口可能不兼容,但内部实现功能满足需求。适配器模式通过转换成客户把接口转换成用户需求的接口来讲不兼容的类连接在一起。

通过uml来了解一下类适配器是什么样子的吧?更多适配器模式可以参考:http://en.wikipedia.org/wiki/Adapter_pattern或者我的博客:http://www.cnblogs.com/davidwang456/p/3844925.html

进入正题,HandlerAdapter定义如下:

org.springframework.web.servlet
Interface HandlerAdapter

All Known Implementing Classes:
AbstractHandlerMethodAdapter, AnnotationMethodHandlerAdapter, HttpRequestHandlerAdapter, RequestMappingHandlerAdapter, SimpleControllerHandlerAdapter, SimpleServletHandlerAdapter 

--------------------------------------------------------------------------------

public interface HandlerAdapterMVC framework SPI, allowing parameterization of the core MVC workflow.
Interface that must be implemented for each handler type to handle a request. This interface is used to allow the DispatcherServlet to be indefinitely extensible. The DispatcherServlet accesses all installed handlers through this interface, meaning that it does not contain code specific to any handler type. 

Note that a handler can be of type Object. This is to enable handlers from other frameworks to be integrated with this framework without custom coding, as well as to allow for annotation-driven handler objects that do not obey any specific Java interface. 

This interface is not intended for application developers. It is available to handlers who want to develop their own web workflow. 

Note: HandlerAdapter implementors may implement the Ordered interface to be able to specify a sorting order (and thus a priority) for getting applied by the DispatcherServlet. Non-Ordered instances get treated as lowest priority.

红色的那句话,画龙点睛之笔:Dispatcher通过handlerAdapter获取所有安装的handler,这就意味着HandlerAdapter不会指定handler类型。

我们看到HandlerAdapter接口有一个实现类:SimpleControllerHandlerAdapter,是不是想到了什么?

public class SimpleControllerHandlerAdapter
extends Object
implements HandlerAdapterAdapter to use the plain Controller workflow interface with the generic DispatcherServlet. Supports handlers that implement the LastModified interface.
This is an SPI class, not used directly by application code.

如果你还没有联想到什么?那么我们来看看这段代码吧

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

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

现在心底的谜底真相大白了吧。

小结:

本文只要讲解request如何通过Dispatcher前端控制器来获取到Controller,现有能力和篇章,有一些地方不够清晰,请见谅!预告:下一篇将是request如何通过Controller获取ModelAndView。

时间: 2024-08-07 16:58:13

spring mvc DispatcherServlet详解之---获取控制器的相关文章

spring mvc DispatcherServlet详解之一---前端控制器架构

前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现(Struts2采用这种方式),也可以使用Servlet来实现(spring MVC框架). DispatcherServlet 作为前置控制器是web服务器的入口,是spring mvc最重要的一个类,通过它的生命周期可以加深对web服务器的理解. servlet的生命周期 首先我们回忆一下ser

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

整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet通过request获取控制器Controller的过程,现在来讲解DispatcherServletDispatcherServlet的第二步:通过request从Controller获取ModelAndView. DispatcherServlet调用Controller的过程: DispatcherServlet.java doService()--->doDispatch()--->handler

spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程

整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet第二步:通过request从Controller获取ModelAndView.现在来讲解第三步:request 从ModelAndView中获取view对象. 获取view对象一般是通过viewResolver来解析view name来完成的.若ModelAndView中view 不存在或者ModelAndView本身为null则填充默认值.代码如下: ModelAndView中view 不存在或者Mod

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

要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构: 从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServlet 就完全可以说弄清楚了spring mvc. 为了加深对spring mvc的整个工作流程的理解,本文从分析DispatcherServlet的工作过程来一窥spring mvc的整个面貌. 1. 初始化 protected void initStrategies(ApplicationCont

spring mvc DispatcherServlet详解之---视图渲染过程

整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的最后一步:视图渲染.视图渲染的过程是在获取到ModelAndView后的过程. 视图渲染的过程: DispatcherServlet.java doService()--->doDispatch()--->processDispatchResult()--->render() processDispatchResult():主要处理异常.请求状态及触发请求完成事件,

spring mvc DispatcherServlet详解之前传---FrameworkServlet

做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationContext. 首先我们来了解applicationContext 和WebapplicationContext区别和联系吧 1. ApplicationContext和WebApplicationContext是继承关系 /** * Interface to provide configuration

spring mvc DispatcherServlet详解之interceptor和filter的区别

首先我们看一下spring mvc Interceptor的功能及实现: http://wenku.baidu.com/link?url=Mw3GaUhCRMhUFjU8iIDhObQpDcbmmRy_IPeumazg0ppnbmwqFUtLp9kSpuPPpeysf6EnHBLYFeWrbjqMq8BlWKQz_7MSDhGQTVl32fpxCMm SpringMVC 中的Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理,其他的作用比如通过它

spring mvc DispatcherServlet详解之拾忆工具类utils

DispatcherServlet的静态初始化 /** * Name of the class path resource (relative to the DispatcherServlet class) * that defines DispatcherServlet's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties&

转载:Spring MVC配置详解

以下内容引自:http://www.cnblogs.com/superjt/p/3309255.html spring MVC配置详解 现在主流的Web MVC框架除了Struts这个主力 外,其次就是Spring MVC了,因此这也是作为一名程序员需要掌握的主流框架,框架选择多了,应对多变的需求和业务时,可实行的方案自然就多了.不过要想灵活运用Spring MVC来应对大多数的Web开发,就必须要掌握它的配置及原理. 一.Spring MVC环境搭建:(Spring 2.5.6 + Hiber