spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程

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

spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程_第1张图片

现在来讲解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。

 

你可能感兴趣的:(spring,mvc)