[细节]Tomcat对静态资源的缓存支持
来源:互联网 发布:中国软件资讯网 编辑:程序博客网 时间:2024/05/01 22:11
使用tomcat时我们可以通过配置DefaultServlet来支持对静态资源的访问,而DefaultServlet是具有缓存功能的,下面通过对关键的源码对其进行分析并介绍如何通过配置来控制tomcat静态资源的缓存行为。
1. 配置DefaultServlet:
我们有两种方式来配置资源,一种是通过部署描述符,另一种就是通过代码进行配置:
通过代码配置DefaultServlet:
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.css</url-pattern></servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.gif</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.jpg</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.js</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.swf</url-pattern> </servlet-mapping>
container.getServletRegistration("default").addMapping("/resource/*");
这句代码在ServletContainerInitializer(Servlet 3.0之后)的onStartUp方法中,这个事件点是应用程序程序开始我们能到达的最早点,在ServetContextListener的contextInitialized方法之前。因为DefaultServlet实例tomcat会默认创建,因此我们可以通过上面的语句直接映射到指定的静态资源路径。
2. DefaultServlet的关键方法:
既然是HttpServlet的子类,我们首先看看doGet方法:
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Serve the requested resource, including the data content serveResource(request, response, true, fileEncoding); }
下面是serveResource方法的一些关键逻辑:
根据路径获取资源对象:
<span style="white-space:pre"></span>WebResource resource = resources.getResource(path);
当资源是文件时,检查相关头部,其中checkIfHeaders方法中就对Etag和lastModified头进行检查:
<span style="white-space:pre"></span>if (resource.isFile()) { // Checking If headers included = (request.getAttribute( RequestDispatcher.INCLUDE_CONTEXT_PATH) != null); if (!included && !isError && !checkIfHeaders(request, response, resource)) { return; } }
<span style="white-space:pre"></span>protected boolean checkIfHeaders(HttpServletRequest request, HttpServletResponse response, WebResource resource) throws IOException { return checkIfMatch(request, response, resource) && checkIfModifiedSince(request, response, resource) && checkIfNoneMatch(request, response, resource) && checkIfUnmodifiedSince(request, response, resource); }可以看到checkIfHeaders方法检查了4个头:If-Match、If-Modified-Since、If-None-Match、If-Unmodified-Since;
其中如果设置If-None-Match的话,If-Modified-Since会忽略,这两个头分别对应于Etag和Last-Modified,如果没有改变,返回304 Not Modified,对应的方法返回false;
而If-Match头和If-Unmodified-Since头分别表示Etag和last-modified值未改变应该返回文件数据(200 OK),对应的方法返回true,如果不相等返回状态码412,方法返回false;
PS:If-Modified-Since和If-None-Match方法会设置last-modified和Etag响应头;
由此可见,只要这个4个方法任何一个返回了false,都直接返回,不返回文件数据,有两种可能:304, 412;
如果上一步没有return,那么应当返回文件数据:
获取资源对象的eTag和lastModifiedHttp并设置响应的头;
<span style="white-space:pre"></span>String eTag = null; String lastModifiedHttp = null; if (resource.isFile() && !isError) { eTag = resource.getETag(); lastModifiedHttp = resource.getLastModifiedHttp(); }
上述过程展示了在什么情况下返回:200, 304, 412;那么Tomcat是如何保存Etag和Last-Modified值的呢?关键在与resources.getResource(path);resources的类型是WebResourceRoot,在Tomcat中的实现是StandardContext,我们来看一下getResource方法:
<span style="white-space:pre"></span>private WebResource getResource(String path, boolean validate, boolean useClassLoaderResources) { if (validate) { path = validate(path); } if (isCachingAllowed()) { return cache.getResource(path, useClassLoaderResources); } else { return getResourceInternal(path, useClassLoaderResources); } }cachingAllowed的值默认为true,还有一个相关的值maxSize(Cache类的成员变量),它们在server.xml的<Context>节点中设置:
<span style="white-space:pre"></span><ContextcrossContext="true"privileged="true"path=""docBase="/usr/local/example.war"reloadable="false"unpackWAR="true"<span style="color:#ff0000;">cachingAllowed</span>="true"<span style="color:#ff0000;">cacheMaxSize</span>="1024"></Context>Cache类负责了实际的缓存工作:开启了缓存之后,会将Resource对象放到一个ConcurrentMap中:
private final ConcurrentMap<String,CachedResource> resourceCache = new ConcurrentHashMap<>();
0 0
- [细节]Tomcat对静态资源的缓存支持
- tomcat和jetty对静态资源的处理和客户端缓存的处理
- tomcat缓存静态资源深入
- tomcat缓存静态资源深入
- SpringMVC对静态资源进行缓存
- SpringMVC对Rest风格的支持和静态资源文件的引用
- Tomcat对https的支持
- 利用Proxy Cache使Nginx对静态资源进行缓存
- 利用Proxy Cache使Nginx对静态资源进行缓存
- 利用Proxy Cache使Nginx对静态资源进行缓存
- 变态的静态资源缓存与更新
- eclipse的静态资源文件夹缓存问题
- Nginx的静态资源缓存以及压缩
- 变态的静态资源缓存与更新
- 前端静态资源缓存的解决方案
- 变态的静态资源缓存与更新
- 变态的静态资源缓存与更新
- nginx静态资源设置缓存的方法
- Spark_GraphX安装记录
- java 中访问控制 public、private 和 protected 介绍
- sicily 1128. DICE
- runtime 运行时机制
- Java的开发模型——Model1和Model2……
- [细节]Tomcat对静态资源的缓存支持
- Java集合框架
- 图解电脑上Firefox浏览器无法打开的解决办法
- 关于Android的隐式意图(调用系统图库和照相机设置图片)
- Java序列化与反序列化
- hdu 4027(区间更新)
- 概率论:高斯/正态分布
- CodeForces 73C LionAge II
- sicily 1129. ISBN