转载

ssm框架系列(3)-前端控制器

上一篇对SpringMVC的处理器映射器和适配器根据实例做了一个整体的介绍,也略微涉及到前端控制器的用法,这一篇将对前端控制器的流程以及使用做一个较为详细的介绍。

配置

第一种:*.action,访问以.action结尾 由DispatcherServlet进行解析

第二种:/,所以访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析,使用此种方式可以实现RESTful风格的url

在平常开发中使用第一种配置方法较多。

DispatcherServlet解析请求的过程图

ssm框架系列(3)-前端控制器

①:DispatcherServlet是springmvc中的前端控制器,负责接收request并将request转发给对应的处理组件。

②:HanlerMapping是springmvc中完成url到controller映射的组件。DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller。

③:Cntroller处理request,并返回ModelAndView对象,Controller是springmvc中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件。

④ ⑤ ⑥:视图解析器解析ModelAndView对象并返回对应的视图给客户端

总的来说,前端控制器用来维护url和controller的映射,具体做法是对标记@Controller类中标识有@RequestMapping的方法进行映射。

在@RequestMapping里边定义映射的url。

DispatcherServlet作用分析

DispatcherServlet 是web服务器的入口,它继承自抽象类FrameworkServlet,也就是间接继承了HttpServlet。我们大家都知道,Servlet的生命周期是:初始化阶段——响应客户请求阶段——销毁。

DispatcherServlet也是一种Servlet。所以,它的生命周期也分为这三个阶段,借助DispatcherServlet的生命周期的源码,我们可以对它有一个更好的理解。

初始化阶段

DispatcherServlet继承FrameworkServlet类,使用initStrategies()方法初始化

protected void initStrategies(ApplicationContext context) {
     initMultipartResolver(context); 
     //文件上传解析
     initLocaleResolver(context);    
     //本地化解析         
     initThemeResolver(context);        //主题解析         
     initHandlerMappings(context);   
     //通过HandlerMapping,将请求映射到处理器         
     initHandlerAdapters(context);   
     //通过HandlerAdapter支持多种类型的处理器         
     initHandlerExceptionResolvers(context); 
     //如果执行过程中遇到异常将交给HandlerExceptionResolver来解析         
     initRequestToViewNameTranslator(context); 
     //直接解析请求到视图名         
     initViewResolvers(context);      
     //通过ViewResolver解析逻辑视图名到具体视图实现         
     initFlashMapManager(context);   
     //flash映射管理器     
  }

响应客户请求阶段

/**
     * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
     * for the actual dispatching.
     */@Overrideprotected 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);
            }
        }
    }

其中, doDispatch(request, response); 实现请求的分发,流程是:

1. 把请求分发到handler(按照配置顺序获取servlet的映射关系获取handler);

2. 根据servlet已安装的  HandlerAdapters 去查询第一个能处理的handler;

3. handler激发处理请求

doDispatch() 方法中的几个重要方法

getHandler(processedRequest) 

获取类HandlerExecutionChain ,存放这个 url 请求的各种信息的类(bean , method ,参数 , 拦截器 ,beanFactory 等等)

getHandlerAdapter(mappedHandler.getHandler()) 

        获取请求处理类 handlerAdapter ( 通过handlerAdapter类的 supports() 方法判断)

  ha.handle(processedRequest, response, mappedHandler.getHandler())

返回 ModelAndView 视图(以及response)

         processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)

结果处理方法以及异常处理

销毁阶段

public void destroy() {
        getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");        
// Only call close() on WebApplicationContext if locally managed...
        if (this.webApplicationContext instanceof 
                ConfigurableApplicationContext && !this.webApplicationContextInjected) {
            ((ConfigurableApplicationContext) this.webApplicationContext).close();
        }
    }

最后,展示基于注解的完整的springMVC配置文

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.amuxia.controller">
    </context:component-scan>

    <mvc:annotation-driven></mvc:annotation-driven>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 配置jsp路径的前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 配置jsp路径的后缀 -->
        <property name="suffix" value=".jsp"/>
    </bean></beans>

总结

前端控制器的基本工作流程是:一个http请求到达服务器,被DispatcherServlet接收,DispatcherServlet将请求委派给合适的处理器Controller。

此时处理控制权到达Controller对象。Controller内部完成请求的数据模型的创建和业务逻辑的处理,然后再将填充了数据后的模型(model)和控制权一并交还给DispatcherServlet,委派DispatcherServlet来渲染响应。

DispatcherServlet再将这些数据和适当的数据模版视图结合,向Response输出响应。

Java知音公众号后续将会系统的整理发布一系列关于ssm框架的知识点,由浅入深。结合小例子来感受ssm框架给我们开发带来的便利,如果您有好的Demo或者文章,欢迎投稿!

ssm框架系列(3)-前端控制器

原文  https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247483736&idx=1&sn=d5ae127906d4b234fedb6c0bb1e0958a&chksm=ebd63e74dca1b76283edb36b032c57f76f90d9aa4204204cd1c398e465108694d2b47be35be9#rd
正文到此结束
Loading...