SpringMVC源码解析之Last-Modified缓存机制

举报
JavaEdge 发表于 2021/06/04 00:42:37 2021/06/04
【摘要】 Spring MVC 支持HTTP协议的 Last-Modified 缓存机制。 支持上次修改的HTTP请求,以方便内容缓存。 相同的合同作为Servlet API中的getLastModified方法。 通过委派到org.springframework.web.servlet.HandlerAdapter.getLastModified实施。 默认情况下,任何控制器...

Spring MVC 支持HTTP协议的 Last-Modified 缓存机制。

支持上次修改的HTTP请求,以方便内容缓存。 相同的合同作为Servlet API中的getLastModified方法。
通过委派到org.springframework.web.servlet.HandlerAdapter.getLastModified实施。 默认情况下,任何控制器或HttpRequestHandler Spring的默认框架内可以实现此接口,以实现最后修改时间检查。
注:另类处理的实现方法有不同的最后修改的处理方式。 例如,Spring 2.5的(使用注释的控制器的方法@RequestMapping )通过提供上次修改支持org.springframework.web.context.request.WebRequest.checkNotModified方法,允许主处理程序方法中最后一次修改检查。

在客户端地一次输入URL时,服务器端会返回内容和状态码200, 表示请求成功,同时会添加一个“Last-Modified”属性,表示该请求资源的最后修改时间
客户端第二次请求此URL时,客户端会向服务器发送请求头 “IF-Modified-Since”,如果服务端内容没有变化,则自动返回HTTP304状态码(只返回相应头信息,不返回资源文件内容,这样就可以节省网络带宽,提供响应速度和用户体验)
Spring MVC 中实现示例

UserCacheController.java
@Controller
public class UserCacheController extends AbstractController implements LastModified{ private long lastModified = System.currentTimeMillis(); protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception { List<User> userList = new ArrayList<User>(); userList.add(new User("zhangsan", 18)); userList.add(new User("wangwu", 16)); System.out.println("执行一次,我有缓存"); return new ModelAndView("userList", "users", userList); } @Override public long getLastModified(HttpServletRequest request) { //时间戳逻辑,返回最后修改时间,例如 if (lastModified == 0L) { lastModified = System.currentTimeMillis(); } System.out.println("时间戳:"+lastModified); return lastModified; }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

Spring MVC 提供的Last-Modified机制的支持,只需要实现LastModified接口,并实现

GetLastModified() 方法

相同的合同为的HttpServlet的getLastModified方法。 请求处理之前调用。
返回值将被发送到HTTP客户端作为Last-Modified头,并与如果-Modified-Since的标头,该客户端发回。 内容将只得到再生,如果出现了修改

每次修改资源的时候,更新下lastModified的值即可。

访问效果

只有第一次执行了Controller,以后访问都没执行Controller。

原理分析DispatcherServlet.doDispatch()

首先获取 http 请求的method type。
如果method 是 “GET”或“HEAD” 才支持缓存机制
通过 HandlerAdapter.getLastModified() 方法获取 UserCacheController 中的lastModified 的值,最后修改时间。
调用 checkNotModified() 方法验证 http 请求头中的“If-Modified-Since”的时间进行对比,判断页面是否更新过。如果有更新才执行具体的Controller, 没有更新则响应 304 状态码信息(HTTP 304: Not Modified )。
getLastModified()

通过handler的适配器类,然后在调用UserCacheController.getLastModified() 方法获取最后更新时间。

checkNotModified()
Paste_Image.png
调用 validateIfModifiedSince() 方法获取http请求头中的“If-Modified-Since”值,并验证是否修改过。
没有修改过则设置notModified=true,如果修改过则设置notModified=false。
如果 notModified=true,则设置response响应状态码304或412
如果是GET 或 HEAD 请求则添加响应头“Last-Modified”
validateIfModifiedSince()

解析http 请求头中的“If-Modified-Since”值
判断缓存页面是否需要更新。
注:(lastModifiedTimestamp / 1000 * 1000):因为http头中只保存到秒,所以这里把秒后面的置为0。
HTTP 请求响应头分析

通过浏览器F12 可以看出:

每次请求都会携带“If-Modified-Since”信息到服务器验证资源是否需要更新。
服务器响应头中会包含“Last-Modified”信息,访问资源最后修改的日期。
缓存限制条件

并非MappingHandler都支持缓存

比如:DefaultAnnotationHandlerMapping 就不支持缓存机制。
因为支持注解的Controller中可以有多个请求方法,而每个方法都需要计算文件的最后修改时间,这样LastModified就不适用了。只适用一个Controller中只支持一个请求的HandlerMapping。

AnnotationMethodHandlerAdapter

  • 方法永远返回-1。

    这个方法总是返回-1,因为带注解的控制器可以有许多方法,每个方法需要单独的上次更改时间的计算。 相反, RequestMapping注解的方法可以计算出上次更改时间值,调用org.springframework.web.context.request.WebRequest.checkNotModified(long) ,以检查它,并返回null如果返回true

文章来源: javaedge.blog.csdn.net,作者:JavaEdge.,版权归原作者所有,如需转载,请联系作者。

原文链接:javaedge.blog.csdn.net/article/details/106546018

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。