引入:
现在我们接着上文章讨论来解决疑问3:对于缓存文件已经存在和不存在的情况有什么特别处理。
分析:
现在我们先来看下如果缓存文件已经存在时候的处理方式:
因为我们开始已经创建了一个缓存文件,它的base名字为$CATALINA_TMPDIR/liferay/css/portal/6476841388170400461
假定我们上次访问的路径是main.css文件,那么这次当我们再访问main.css文件的时候,我们就发现它走了第120行。它会先判断缓存文件的最后修改时间戳(cacheDataFile.lastModified())和原始文件的最后修改时间戳(file.lastModified()),如果前者偏大,则说明缓存文件是最新的,那么它就124行直接把缓存文件的内容类型文件的contentType读取出来,然后
第126行吧httpServletResponse的返回类型设置为这个缓存文件内容类型(回想以前曾说过,第一次设置时候这个值应该是text/css),最后吧缓存的数据文件放到输出流中。
然后在第DynamicCSSFilter中第217行用
使用ServletResponseUtil 读取这个缓存文件中的内容并且输出到客户端。
所以客户端就可以获得最新版本的解析后的普通css资源文件并且使用了。(这个过程中并没有JRuby解析Sass生成css,所以减少好多IO操作,效率提高了很多)
下面我们再来看下缓存不存在,从头生成这些文件的例子:
假如我们清空了tomcat的temp目录吧这些缓存文件都清空,那么显然,它没办法走缓存路线(也就是不走if(cacheDataFile.exists()分支),所以它会去生成新的。
让我们回到原始的讨论,如下所示,在142行是从原始的带Sass的样式文件中读取的css文件,存放到content中
然后第144行解析Sass文件获取的普通css文件存放到dynamicContent中,我们可以比较看出明显不同.
尤其是在@import这种语法后,转为的新的都加了很多参数。
这时候,调用第149行的FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS)会写入内容类型文件:
从服务器看,当前目录下只有一个文件<baseName>_E_CONTENT_TYPE,这是合乎情理的,因为数据文件还没创建呢,才刚刚写内容类型文件,而且写的时间也和当前的时间戳吻合,说明是刚才才写入的这个文件,并且这个文件内容只有text/css,所以这个文件很小,只有8个字节。
然后第193行,就会吧生成的普通css文件内容(也就是存放在dynamicContent变量中)写入到数据文件中,调用是第193行FileUtil.write(cacheDataFile.dynamicContent);
我们看下服务器目录,果然现在生成了<baseName>_E_DATA文件:
这个文件从时间戳看比刚才的内容文件晚5分钟,这也合乎常理,因为我在调试,要单步走,并且还有截图,写文章,所以确信,这正是调试点所执行到时候创建的文件,并且文件大小是874字节,这个也刚好和我们的dynamicContent的大小一样,如下图:
一切都是那么吻合和完美。
结论:
(1)当请求的资源文件已经在Liferay的缓存中(也就是在$CATALINA_TMPDIR/liferay/css/folder/<hashcode>时候,服务器会去比较缓存中的资源文件的最近使用时间戳和原始资源文件的最近使用时间戳,如果缓存的时间戳比较新,那么就直接从缓存中读取内容类型信息和被解析后的普通css文件,然后构造输出流输出到客户端。
(2)当请求的资源文件没有在Liferay缓存中,那么Liferay框架会自己在缓存目录中构建相应的目录和文件,并且先是写内容类型文件,再写缓存数据文件(Sass解析后得到的普通css文件),最终把这些内容通过输出流输出到客户端。