(5)SpringMVC-http请求处理路线

 


 

核心架构的具体流程步骤如下:

1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;

2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略;

3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;

4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名);

5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;

6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;

7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。

 

用我的话来概括如下:

    由HandlerMapping得到HandlerExecutionChain(其包含Object handler,interceptors),handler就是Controller实例,接着由handler得到HandlerAdapter(ha),最后由ha.handle(..)得到ModelAndView。注意,在执行目标方法之前,会升序调用interceptors,之后又会倒序调用interceptors。那么,HandlerAdapter是个什么东西呢,我在DispatcherServlet.properties里可以看到默认配了3种adapter,其实还有一种adapter没加进配置文件,如果你了解springmvc的发展史和解决mvc的思路,你就会明白为什么有多种实现方式了。最初springmvc采用的是实现Controller接口的方式,javase 1.5开始,springmvc采用了更方便的注解方式来标明Controller类,这两种方式对应的adapter分别是SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,所以我们可以重点关注AnnotationMethodHandlerAdapter。

 

下面来好好谈谈DispatcherServlet的部分代码

    我们注意到该类中定义了一些well-known常量,呵呵,众所周知的常量

public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";  
  
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";  
  
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";  
  
/** 
 * Well-known name for the HandlerMapping object in the bean factory for this namespace. 
 * Only used when "detectAllHandlerMappings" is turned off. 
 * @see #setDetectAllHandlerMappings 
 */  
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";  
  
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";  
  
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";  
  
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";  
  
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";  
  
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";  
  
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties"; 

 

 我们在配置文件中给相关组件bean命名时,可以保持和只写常量值一致,毕竟别人的命名是相当标准的,不过,这从逻辑上不是必须的,你甚至可以不声明bean的id,因为该类提供了如下变量

/** Detect all HandlerMappings or just expect "handlerMapping" bean? */  
    private boolean detectAllHandlerMappings = true;  
  
    /** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */  
    private boolean detectAllHandlerAdapters = true;  
  
    /** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */  
    private boolean detectAllHandlerExceptionResolvers = true;  
  
    /** Detect all ViewResolvers or just expect "viewResolver" bean? */  
    private boolean detectAllViewResolvers = true;  
  
    /** Perform cleanup of request attributes after include request? */  
    private boolean cleanupAfterInclude = true;  
  
    /** MultipartResolver used by this servlet */  
    private MultipartResolver multipartResolver;  
  
    /** LocaleResolver used by this servlet */  
    private LocaleResolver localeResolver;  
  
    /** ThemeResolver used by this servlet */  
    private ThemeResolver themeResolver;  
  
    /** List of HandlerMappings used by this servlet */  
    private List<HandlerMapping> handlerMappings;  
  
    /** List of HandlerAdapters used by this servlet */  
    private List<HandlerAdapter> handlerAdapters;  
  
    /** List of HandlerExceptionResolvers used by this servlet */  
    private List<HandlerExceptionResolver> handlerExceptionResolvers;  
  
    /** RequestToViewNameTranslator used by this servlet */  
    private RequestToViewNameTranslator viewNameTranslator;  
  
    /** FlashMapManager used by this servlet */  
    private FlashMapManager flashMapManager;  
  
    /** List of ViewResolvers used by this servlet */  
    private List<ViewResolver> viewResolvers; 

 

初始化方法中,执行了组件的初始化

protected void initStrategies(ApplicationContext context) {  
    initMultipartResolver(context);  
    initLocaleResolver(context);  
    initThemeResolver(context);  
    initHandlerMappings(context);  
    initHandlerAdapters(context);  
    initHandlerExceptionResolvers(context);  
    initRequestToViewNameTranslator(context);  
    initViewResolvers(context);  
    initFlashMapManager(context);  
}

  

 我们拿出initHandlerMappings(context)来瞅瞅

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

 

 通过该方法我们可以知道,当detectAllHandlerMappings为true时,直接到mvc容器及其父容器中寻找所有类型为HandlerMapping的bean,而detectAllHandlerMappings默认恰为true,因此我们完全可以不声明bean的id。当detectAllHandlerMappings为false时(可通过在web.xml里配置servlet参数来改变默认值),则在mvc容器寻找名为"handlerMapping"的bean。如以上两种情况都没找到bean,将会实例化DispatcherServlet.properties中配置的bean。

    doService方法里有这么一段

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

  

 这是用于对页面有include的情况做的请求数据快照处理。

下面进入重点doDispatch方法

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 {  
            // multipart包装处理,我们常用CommonsMultipartResolver  
                                processedRequest = checkMultipart(request);  
                multipartRequestParsed = processedRequest != request;  
  
                // Determine handler for the current request.  
                mappedHandler = getHandler(processedRequest, false);  
                if (mappedHandler == null || mappedHandler.getHandler() == null) { // 404  
                    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.  // 代码省略  
                  
                                // 调用目标方法前,顺序执行拦截器  
                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);  
            }  
        }  
    }  

 

HandlerExecutionChain 

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {  
        if (getInterceptors() != null) {  
            for (int i = 0; i < getInterceptors().length; i++) {  
                HandlerInterceptor interceptor = getInterceptors()[i];  
                if (!interceptor.preHandle(request, response, this.handler)) {  
                    triggerAfterCompletion(request, response, null);  
                    return false;  
                }  
                this.interceptorIndex = i;  
            }  
        }  
        return true;  
    }  
  
    /** 
     * Apply postHandle methods of registered interceptors. 
     */  
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {  
        if (getInterceptors() == null) {  
            return;  
        }  
        for (int i = getInterceptors().length - 1; i >= 0; i--) {  
            HandlerInterceptor interceptor = getInterceptors()[i];  
            interceptor.postHandle(request, response, this.handler, mv);  
        }  
    }  
  
    /** 
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. 
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation 
     * has successfully completed and returned true. 
     */  
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)  
            throws Exception {  
  
        if (getInterceptors() == null) {  
            return;  
        }  
        for (int i = this.interceptorIndex; i >= 0; i--) {  
            HandlerInterceptor interceptor = getInterceptors()[i];  
            try {  
                interceptor.afterCompletion(request, response, this.handler, ex);  
            }  
            catch (Throwable ex2) {  
                logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);  
            }  
        }  
    } 

 

HandlerInterceptor

public interface HandlerInterceptor {  
  
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
        throws Exception;  
  
    void postHandle(  
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)  
            throws Exception;  
  
    void afterCompletion(  
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)  
            throws Exception;  
  
} 

 

 自定义

public class ExceptionHandler implements HandlerExceptionResolver {  
  
    @Override  
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {  
        request.setAttribute("exception",ex.getMessage());  
        ModelAndView mav = new ModelAndView();  
        mav.setViewName("/error");  
        return mav;  
    }  
} 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武汉红喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值