打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
spring学习笔记之AbstractController源码解读

spring学习笔记之AbstractController源码解读

Spring 学习笔记(二)-- AbstactController

控制器是 MVC 设计模式的一部分,通过定义服务接口提供对应用行为的访问。控制器获取用户输入的数据并作简单的转换处理成符合服务模块的规则并传入服务模块,经过服务模块的处理给用户返回视图。 Spring 的控制器以抽象的方式实现了这种概念,并且有很多样的控制器在不同情况下可供使用,包括了确定视图的控制器,基于命令的控制器,还有执行向导式逻辑的控制器,在这里仅举几个例子。

Spring 的控制器结构的基础是 org.springframework.web.servlet.mvc.Controller 接口。

  1. public interface Controller {  
  2.     /** 
  •      * Process the request and return a ModelAndView object which the DispatcherServlet 
  •      * will render. 
  •      */  
  •     ModelAndView handleRequest(  
  •         HttpServletRequest request,  
  •         HttpServletResponse response) throws Exception;  
  • }  
  • 可以看到, Controller 接口定义了一个方法,负责处理一个请求并通过合适的模块返回视图。在 Spring 通过 ModelAndView 和 Controller 实现。 Controller 接口是非常抽象的, Spring 提供许多实现了这个接口的控制器,这些控制器包含了许多功能,在你需要的时候可以使用。而 Controller 接口只是定义了一个方法负责最基本的职责。

    Spring 定义的控制器并不是直接实现 Controller 接口,而是实现了 AbstractController,AbstractorController 实现了 Controller 接口。

    下面表格是 AbstractController 提供的功能点。

    Feature

    说明

    supportMethods

    表明控制器会接收哪些方法。一般会默认设置GET 和POST ,你也可以修改这些方法。如果一个请求携带的方法是这个控制器不支持的,客户端会被告知,抛出ServletException 。

    requireSession

    表明控制器是否需要HTTP session 。

    synchronizeOnSession

    确定是否对HTTP session 实行同步。

    cacheSeconds

    设置cache 时间。默认是-1 ,则不设置。

    useExpiresHeader

    为了与HTTP1.0 的‘Expires’ 兼容. 默认true

    useCacheHeader

    为了与HTTP1.0 的‘Cache-Control’ 兼容,默认true

    当你用 AbstractController 作为你控制器的父类的时候,你只需要改写 handleRequestInternal(HttpServletRequest, HttpServletResponse) 方法,实现业务逻辑,并返回 ModelAndView 对象。下面是一个下面是一个例子。

    1. public class SampleController extends AbstractController {  
    2.     public ModelAndView handleRequestInternal(  
  •         HttpServletRequest request,  
  •         HttpServletResponse response) throws Exception {  
  •         ModelAndView mav = new ModelAndView("hello");  
  •         mav.addObject("message""Hello World!");  
  •         return mav;  
  •   }  
  • }  
    1. <bean id="sampleController" class="samples.SampleController">  
    2.     <property name="cacheSeconds" value="120"/>  
  • </bean>  
  • <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    上面这个控制器产生了 cache 指令告诉客户端 cache 保持 2 分钟。我们看到一个编码的坏习惯,就是返回视图的时候用了硬编码。

    上面讲到的是从 spring-reference.pdf 翻译过来的,部分加上自己的理解。现在再结合源码可以更深入的了解到上面的机制是怎么运行的。

    首先我们现看一下 AbstractController 的类层次图。

    <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    似比较复杂。一步一步来看。

    现看 AbstractController 类。 Spring 定义的所有控制器都继承于它。它有一个属性

    private boolean synchronizeOnSession = false ;

    这个属性的作用在上面有提到过。上面提到的其他属性在 AbstractController 的父类定义。

    另外就是实现了 Controller 接口的方法:

    1. public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)  
    2.             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);  
  •     }  
  • <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    首先是委托 WebContentGenerator 作一些准备的工作。作一些什么样的工作呢?我们再看 WebContentGenerator checkAndPrepare () 方法。注意一下, WebContentGenerator 初始化时将默认的处理方法为 get,post,head 。代码如下:

    1. public WebContentGenerator(boolean restrictDefaultSupportedMethods) {  
    2.         if (restrictDefaultSupportedMethods) {  
  •             this.supportedMethods = new HashSet(4);  
  •             this.supportedMethods.add(METHOD_GET);  
  •             this.supportedMethods.add(METHOD_HEAD);  
  •             this.supportedMethods.add(METHOD_POST);  
  •         }  
  •     }  
  • <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    restrictDefaultSupportedMethods 默认为 true

    1. protected final void cacheForSeconds(HttpServletResponse response, int seconds, boolean mustRevalidate) {  
    2.         if (this.useExpiresHeader) {  
  •             // HTTP 1.0 header   
  •             response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L);  
  •         }  
  •         if (this.useCacheControlHeader) {  
  •             // HTTP 1.1 header   
  •             String headerValue = "max-age=" + seconds;  
  •             if (mustRevalidate) {  
  •                 headerValue += ", must-revalidate";  
  •             }  
  •             response.setHeader(HEADER_CACHE_CONTROL, headerValue);  
  •         }  
  •     }  
  • this . useExpiresHeader 处理根据上文知道是为了兼容 HTTP1.0.

    this . useCacheControlHeader 如果用户有使用 cache 指令,则进行处理,用 Servlet 最基本的 response 设置。


    1. protected final void checkAndPrepare(  
    2.             HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)  
  •         throws ServletException {  
  •         // Check whether we should support the request method.   
  •         String method = request.getMethod();  
  •         if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {  
  •             throw new HttpRequestMethodNotSupportedException(  
  •                     method, StringUtils.toStringArray(this.supportedMethods));  
  •         }  
  •         // Check whether a session is required.   
  •         if (this.requireSession) {  
  •             if (request.getSession(false) == null) {  
  •                 throw new HttpSessionRequiredException("Pre-existing session required but none found");  
  •             }  
  •         }  
  •         // Do declarative cache control.   
  •         // Revalidate if the controller supports last-modified.   
  •         applyCacheSeconds(response, cacheSeconds, lastModified);  
  •     }  
  • <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    这段代码结合上文就可以很好的理解 supportMethods 抛出异常的相关情况。

    applyCacheSeconds(response,cacheSeconds,lastModified) 方法中,参数 lastModified 是在 ApplicationController handleRequest() ,有这样传入 this instanceof LastModified ,判断这个控制类是否实现了 LastModified 接口 , 在这个方法实际上作了 cacheSeconds 属性的工作。

    <!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

    常量 HEADER_CACHE_CONTROL =“ Cache-Control” ,这是对 cache 的处理。


    现在回到 AbstractController handleRequests() 方法, checkAndPrepare ()处理完之后,再根据 synchronizeOnSession 判断是否需要同步。 handleRequestInternal(request, response) 方法是真正处理逻辑的地方,这也是前面一个例子为什么要重写这个方法的原因。

    本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
    打开APP,阅读全文并永久保存 查看更多类似文章
    猜你喜欢
    类似文章
    第四章 Controller接口控制器详解(1)——跟着开涛学SpringMVC
    SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
    Spring HandlerInterceptor的使用
    [Java教程]spring mvc 实现网站登录与非登录的控制
    SpringMVC学习笔记(四)
    Spring MVC 中 HandlerInterceptorAdapter的使用
    更多类似文章 >>
    生活服务
    热点新闻
    分享 收藏 导长图 关注 下载文章
    绑定账号成功
    后续可登录账号畅享VIP特权!
    如果VIP功能使用有故障,
    可点击这里联系客服!

    联系客服