在Web应用中
![](/icons/70413dou.gif)
内容缓存Cache是最普通
![](/icons/70413de.gif)
优化技术的
![](/icons/70413yi.gif)
![](/icons/70413dou.gif)
并且能够很容易地实现
![](/icons/70413dou2.gif)
例如
![](/icons/70413dou.gif)
可以使用
![](/icons/70413yi.gif)
个自定义地JSP标签——我们将的命名为<jc:cache>——由<jc:cache>和</jc:cache>将每
![](/icons/70413yi.gif)
个需要被缓存Cache
![](/icons/70413de.gif)
页面片段封装起来
![](/icons/70413dou2.gif)
任何自定义标签可以控制它所包含部分 (也即预先封装
![](/icons/70413de.gif)
页面片段)在何时执行
![](/icons/70413dou.gif)
并且动态输出结果可以被捕获
![](/icons/70413dou2.gif)
<jc:cache>标签使得JSP容器(例如Tomcat)只生成内容
![](/icons/70413yi.gif)
次
![](/icons/70413dou.gif)
作为应用
![](/icons/70413chengxu.gif)
范围内
![](/icons/70413de.gif)
JSP变量
![](/icons/70413dou.gif)
来存储每
![](/icons/70413yi.gif)
个缓存Cache片段
![](/icons/70413dou2.gif)
每次JSP页面被执行时
![](/icons/70413dou.gif)
自定义标签将缓存Cache页面片段载入而无需再次执行JSP代码来生成输出结果
![](/icons/70413dou2.gif)
作为Jakarta工程
![](/icons/70413de.gif)
![](/icons/70413yi.gif)
个部分
![](/icons/70413dou.gif)
标签库
![](/icons/70413de.gif)
开发使用了这项技术
![](/icons/70413dou2.gif)
当被缓存Cache内容无需被每
![](/icons/70413yi.gif)
个用户或者请求所定制
![](/icons/70413de.gif)
时候
![](/icons/70413dou.gif)
它工作
![](/icons/70413de.gif)
十分良好
这篇文章对上面描述
![](/icons/70413de.gif)
技术做了改进
![](/icons/70413dou.gif)
通过使用JSP 2.0表达式语言(EL)
![](/icons/70413dou.gif)
允许JSP页面为每
![](/icons/70413yi.gif)
个请求和用户定制缓存Cache内容
![](/icons/70413dou2.gif)
缓存Cache页面片段可以包含未被JSP容器赋值
![](/icons/70413de.gif)
JSP表达式
![](/icons/70413dou.gif)
在每
![](/icons/70413yi.gif)
次页面被执行时
![](/icons/70413dou.gif)
由自定义标签来确定这些表达式
![](/icons/70413de.gif)
值
![](/icons/70413dou2.gif)
因此
![](/icons/70413dou.gif)
动态内容
![](/icons/70413de.gif)
建立被最优化
![](/icons/70413dou.gif)
但是缓存Cache片段可以含有部分由每
![](/icons/70413yi.gif)
个请求使用本机JSP表达式语言产生
![](/icons/70413de.gif)
内容
![](/icons/70413dou2.gif)
通过JSP 2.0 EL API
![](/icons/70413de.gif)
帮助
![](/icons/70413dou.gif)
Java开发者可以用表达式语言来使的成为可能
内容缓存CacheVS数据缓存Cache 内容缓存Cache不是唯
![](/icons/70413yi.gif)
![](/icons/70413de.gif)
选择
![](/icons/70413dou2.gif)
例如
![](/icons/70413dou.gif)
从数据库中提取
![](/icons/70413de.gif)
数据同样可以被缓存Cache
![](/icons/70413dou2.gif)
事实上
![](/icons/70413dou.gif)
由于存储
![](/icons/70413de.gif)
信息中不包含HTML markup
![](/icons/70413dou.gif)
以及要求较少
![](/icons/70413de.gif)
内存
![](/icons/70413dou.gif)
数据缓存Cache可能更加高效率
![](/icons/70413dou2.gif)
然而在很多情况下
![](/icons/70413dou.gif)
内存缓存Cache更容易实现
![](/icons/70413dou2.gif)
假设在某个案例总
![](/icons/70413dou.gif)
![](/icons/70413yi.gif)
个应用由大量事务对象
![](/icons/70413dou.gif)
占用重要
![](/icons/70413de.gif)
CPU资源
![](/icons/70413dou.gif)
产生复杂
![](/icons/70413de.gif)
数据
![](/icons/70413dou.gif)
并且用JSP页面来呈现这些数据
![](/icons/70413dou2.gif)
工作
![](/icons/70413yi.gif)
切良好
![](/icons/70413dou.gif)
直到某天突然地服务器
![](/icons/70413de.gif)
负载增加
![](/icons/70413dou.gif)
需要
![](/icons/70413yi.gif)
个紧急解决方案
![](/icons/70413dou2.gif)
这时在事务对象和呈现表达层的间建立
![](/icons/70413yi.gif)
个缓存Cache层
![](/icons/70413dou.gif)
时
![](/icons/70413yi.gif)
个非常不错和有效
![](/icons/70413de.gif)
方案
![](/icons/70413dou2.gif)
但是必须非常快速和流畅地修改缓存Cache动态内容
![](/icons/70413de.gif)
JSP页面
![](/icons/70413dou2.gif)
相对于简单
![](/icons/70413de.gif)
JSP页面编辑
![](/icons/70413dou.gif)
应用
![](/icons/70413chengxu.gif)
![](/icons/70413de.gif)
业务逻辑变化通常要求更多
![](/icons/70413de.gif)
工作量和测试;另外
![](/icons/70413dou.gif)
如果
![](/icons/70413yi.gif)
个页面从多个复合源聚合信息时
![](/icons/70413dou.gif)
Web层仅有少量
![](/icons/70413de.gif)
改变
![](/icons/70413dou2.gif)
问题在于
![](/icons/70413dou.gif)
当缓存Cache信息变得失去时效时
![](/icons/70413dou.gif)
缓存Cache空间需要被释放
![](/icons/70413dou.gif)
而事务对象应该知道何时发生这种情况
![](/icons/70413dou2.gif)
然而
![](/icons/70413dou.gif)
选择实现内容缓存Cache还是数据缓存Cache
![](/icons/70413dou.gif)
或者其他
![](/icons/70413de.gif)
优化技术
![](/icons/70413dou.gif)
有很多不得不考虑
![](/icons/70413de.gif)
原因
![](/icons/70413dou.gif)
有时是所开发
![](/icons/70413de.gif)
![](/icons/70413chengxu.gif)
所特殊要求
![](/icons/70413de.gif)
数据缓存Cache和内容缓存Cache没有必要互相排斥
![](/icons/70413dou.gif)
它们可以
![](/icons/70413yi.gif)
起使用
![](/icons/70413dou2.gif)
例如
![](/icons/70413dou.gif)
在数据库驱动
![](/icons/70413de.gif)
应用中;从数据库中提取出来
![](/icons/70413de.gif)
数据
![](/icons/70413dou.gif)
和呈现该数据
![](/icons/70413de.gif)
HTML分别被缓存Cache起来
![](/icons/70413dou2.gif)
这和使用JSP实时生成
![](/icons/70413de.gif)
模板有些相似
![](/icons/70413dou2.gif)
这篇文章中讨论
![](/icons/70413de.gif)
基于EL API技术介绍说明如何使用JSP EL来将数据载入到呈现模板中
使用JSP变量缓存Cache动态内容 每当实现
![](/icons/70413yi.gif)
个缓存Cache机制是
![](/icons/70413dou.gif)
都需要
![](/icons/70413yi.gif)
个存储缓存Cache对象
![](/icons/70413de.gif)
思路方法
![](/icons/70413dou.gif)
在这篇文章中涉及
![](/icons/70413de.gif)
是String类型
![](/icons/70413de.gif)
对象
![](/icons/70413yi.gif)
种选择是使用
![](/icons/70413yi.gif)
个对象——缓存Cache框架结构
![](/icons/70413dou.gif)
或者使用Java maps来实现自定义
![](/icons/70413de.gif)
缓存Cache方案
![](/icons/70413dou2.gif)
JSP已经拥有了称为“scoped attributes”或“JSP variables”来提供ID——object映射
![](/icons/70413dou.gif)
这正是缓存Cache机制所需要
![](/icons/70413de.gif)
![](/icons/70413dou2.gif)
对于使用page或者request scope
![](/icons/70413dou.gif)
这是没有意义
![](/icons/70413de.gif)
![](/icons/70413dou.gif)
而在应用范围内
![](/icons/70413dou.gif)
这是
![](/icons/70413yi.gif)
个很好
![](/icons/70413de.gif)
存储缓存Cache内容
![](/icons/70413de.gif)
位置
![](/icons/70413yinwei.gif)
它被所有
![](/icons/70413de.gif)
用户和页面共享
![](/icons/70413dou2.gif)
当每
![](/icons/70413yi.gif)
个用户需要单独缓存Cache时
![](/icons/70413dou.gif)
Session scope也可以被使用
![](/icons/70413dou.gif)
但这不是很有效率
![](/icons/70413dou2.gif)
JSTL标签库可以被是和那个来缓存Cache内容
![](/icons/70413dou.gif)
通过使用JSP变量正如下例所示:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:
![](/icons/70413if.gif)
test="${empty cachedFragment}">
<c:
![](/icons/70413set.gif)
var="cachedFragment" scope="application">
...
</c:
![](/icons/70413set.gif)
></c:
![](/icons/70413if.gif)
>
缓存Cache页面片段用下列语句输出结果:
${applicationScope.cachedFragment}
当缓存Cache片段需要被每
![](/icons/70413yi.gif)
个请求所定制
![](/icons/70413de.gif)
时候
![](/icons/70413dou.gif)
到底发生了什么?例如
![](/icons/70413dou.gif)
如果希望包含
![](/icons/70413yi.gif)
个计数器
![](/icons/70413dou.gif)
需要缓存Cache两个片段:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:
![](/icons/70413if.gif)
test="${sessionScope.counter
![](/icons/70413dd.gif)
null}"> <c:
![](/icons/70413set.gif)
var="counter" scope="session" value="0"/></c:
![](/icons/70413if.gif)
><c:
![](/icons/70413set.gif)
var="counter" value="${counter+1}" scope="session"/><c:
![](/icons/70413if.gif)
test="${empty cachedFragment1}">
<c:
![](/icons/70413set.gif)
var="cachedFragment1" scope="application">
...
</c:
![](/icons/70413set.gif)
></c:
![](/icons/70413if.gif)
><c:
![](/icons/70413if.gif)
test="${empty cachedFragment2}">
<c:
![](/icons/70413set.gif)
var="cachedFragment2" scope="application">
...
</c:
![](/icons/70413set.gif)
></c:
![](/icons/70413if.gif)
>
可以使用下面语句输出缓存Cache内容:
${cachedFragment1} ${counter} ${cachedFragment2}
通过专门
![](/icons/70413de.gif)
标签库
![](/icons/70413de.gif)
帮助
![](/icons/70413dou.gif)
需要定制
![](/icons/70413de.gif)
页面片段
![](/icons/70413de.gif)
缓存Cache变得异常容易了
![](/icons/70413dou2.gif)
上面已经提及
![](/icons/70413dou.gif)
缓存Cache内容可以被开始标签(<jc:cache>)和结尾标签(</jc:cache>)封装起来
![](/icons/70413dou2.gif)
而每
![](/icons/70413yi.gif)
个定制可以使用另
![](/icons/70413yi.gif)
个标签(<jc:dynamic expr="..."/>)输出
![](/icons/70413yi.gif)
个JSP表达式(${...})来表现
![](/icons/70413dou2.gif)
动态内容用JSP表达式缓存Cache并在每
![](/icons/70413yi.gif)
次缓存Cache内容被输出时赋值
![](/icons/70413dou2.gif)
在下面
![](/icons/70413de.gif)
部分可以看到这是如何实现
![](/icons/70413de.gif)
![](/icons/70413dou2.gif)
Counter.jsp缓存Cache了
![](/icons/70413yi.gif)
个包含计数器
![](/icons/70413de.gif)
页面片段
![](/icons/70413dou.gif)
当每
![](/icons/70413yi.gif)
次用户刷新这个页面
![](/icons/70413de.gif)
时候计数器会自动+1
![](/icons/70413dou2.gif)
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="jc" uri="http://devsphere.com/articles/jspcache" %><c:
![](/icons/70413if.gif)
test="${sessionScope.counter
![](/icons/70413dd.gif)
null}">
<c:
![](/icons/70413set.gif)
var="counter" scope="session" value="0"/></c:
![](/icons/70413if.gif)
><c:
![](/icons/70413set.gif)
var="counter" value="${counter+1}" scope="session"/><jc:cache id="cachedFragmentWithCounter">
... <jc:dynamic expr="sessionScope.counter"/>
...</jc:cache>
JSP 变量易于使用
![](/icons/70413dou.gif)
对于简单
![](/icons/70413de.gif)
Web apps
![](/icons/70413dou.gif)
这是
![](/icons/70413yi.gif)
个不错
![](/icons/70413de.gif)
内容缓存Cache方案
![](/icons/70413dou2.gif)
然而
![](/icons/70413dou.gif)
如果应用
![](/icons/70413chengxu.gif)
产生大量
![](/icons/70413de.gif)
动态内容
![](/icons/70413dou.gif)
没有对缓存Cache大小
![](/icons/70413de.gif)
控制无疑是
![](/icons/70413yi.gif)
个问题
![](/icons/70413dou2.gif)
![](/icons/70413yi.gif)
种专用
![](/icons/70413de.gif)
缓存Cache框架结构能够提供
![](/icons/70413yi.gif)
个更加有力
![](/icons/70413de.gif)
方案
![](/icons/70413dou.gif)
允许对缓存Cache
![](/icons/70413de.gif)
监视
![](/icons/70413dou.gif)
限制缓存Cache大小
![](/icons/70413dou.gif)
控制缓存Cache策略
![](/icons/70413dou.gif)
等等……
使用JSP 2.0表达式语言API JSP容器(例如Tomcat)对应用EL API
![](/icons/70413de.gif)
JSP页面中
![](/icons/70413de.gif)
表达式予以赋值
![](/icons/70413dou.gif)
并且可以被Java代码所使用
![](/icons/70413dou2.gif)
这允许在Web页面外应用JSP EL作开发
![](/icons/70413dou.gif)
例如
![](/icons/70413dou.gif)
对XML文件、基于文本
![](/icons/70413de.gif)
资源以及自定义脚本
![](/icons/70413dou2.gif)
当需要控制何时对Web页面中
![](/icons/70413de.gif)
表达式进行赋值或者书写和的相关
![](/icons/70413de.gif)
表达式时
![](/icons/70413dou.gif)
EL API同样是有用
![](/icons/70413de.gif)
![](/icons/70413dou2.gif)
例如
![](/icons/70413dou.gif)
缓存Cache页面片段可以包含自定义JSP表达式
![](/icons/70413dou.gif)
并且当每
![](/icons/70413yi.gif)
次缓存Cache内容被输出时
![](/icons/70413dou.gif)
EL API将用来给这些表达式赋值或者重新赋值
文章提供了
![](/icons/70413yi.gif)
个例子
![](/icons/70413chengxu.gif)
(参见文末资源部分)
![](/icons/70413dou.gif)
这个应用
![](/icons/70413chengxu.gif)
包含了
![](/icons/70413yi.gif)
个Java类(JspUtils)和类中包含
![](/icons/70413yi.gif)
个思路方法eval
![](/icons/70413kh.gif)
![](/icons/70413dou.gif)
这个思路方法有 3个参数:JSP表达式、表达式
![](/icons/70413de.gif)
期望类型和
![](/icons/70413yi.gif)
个JSP context对象
![](/icons/70413dou2.gif)
Eval
![](/icons/70413kh.gif)
思路方法从JSP context中取得ExpressionEvaluator并且
![](/icons/70413diaoyong.gif)
evaluate
![](/icons/70413kh.gif)
思路方法
![](/icons/70413dou.gif)
通过表达式、表达式
![](/icons/70413de.gif)
期望类型、和
![](/icons/70413yi.gif)
个从JSP congtext中获得
![](/icons/70413de.gif)
变量
![](/icons/70413dou2.gif)
JspUtils.eval
![](/icons/70413kh.gif)
思路方法返回表达式
![](/icons/70413de.gif)
值
![](/icons/70413dou2.gif)
package com.devsphere.articles.jspcache;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.el.ELException;
import javax.servlet.jsp.el.ExpressionEvaluator;
import java.io.IOException;public
![](/icons/70413class.gif)
JspUtils {
public
![](/icons/70413static.gif)
Object eval(
String expr, Class type, JspContext jspContext)
throws JspException {
try {
![](/icons/70413if.gif)
(expr.indexOf("${")
![](/icons/70413dd.gif)
-1)
![](/icons/70413return.gif)
expr;
ExpressionEvaluator evaluator
= jspContext.getExpressionEvaluator
![](/icons/70413kh.gif)
;
![](/icons/70413return.gif)
evaluator.evaluate(expr, type,
jspContext.getVariableResolver
![](/icons/70413kh.gif)
, null);
} catch (ELException e) {
throw
![](/icons/70413new.gif)
JspException(e);
}
}
...}
注意:JspUtils.eval
![](/icons/70413kh.gif)
主要封装了标准
![](/icons/70413de.gif)
ExpressionEvaluator
![](/icons/70413dou2.gif)
如果expr不包含${
![](/icons/70413dou.gif)
JSP EL API不被
![](/icons/70413diaoyong.gif)
![](/icons/70413dou.gif)
![](/icons/70413yinwei.gif)
没有JSP表达式
创建标签库描述符(TLD)文件
JSP标签库需要
![](/icons/70413yi.gif)
个标签库描述符(TLD)文件来自定义标签
![](/icons/70413de.gif)
命名
![](/icons/70413dou.gif)
它们
![](/icons/70413de.gif)
属性
![](/icons/70413dou.gif)
以及操作该标签
![](/icons/70413de.gif)
Java类
![](/icons/70413dou2.gif)
jspcache.tld描述了两个自定义标签
![](/icons/70413dou.gif)
<jc:cache>拥有两个属性:缓存Cache页面片段
![](/icons/70413de.gif)
id和JSP scope—JSP页面总需要被储存
![](/icons/70413de.gif)
内容范围
![](/icons/70413dou2.gif)
<jc:dynamic>只有
![](/icons/70413yi.gif)
个属性
![](/icons/70413dou.gif)
即JSP表达式必须在每
![](/icons/70413yi.gif)
次缓存Cache片段被输出时被赋值
![](/icons/70413dou2.gif)
TLD文件将这两个自定义标签映射到CacheTag和DynamicTag类
![](/icons/70413dou.gif)
如下所示:
<?xml version="1.0" encoding="UTF-8" ?><taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd"
version="2.0">
<tlib-version>1.0</tlib-version>
<
![](/icons/70413short.gif)
-name>jc</
![](/icons/70413short.gif)
-name>
<uri>http://devsphere.com/articles/jspcache</uri>
<tag>
<name>cache</name>
<tag-
![](/icons/70413class.gif)
>com.devsphere.articles.jspcache.CacheTag</tag-
![](/icons/70413class.gif)
>
<body-content>scriptless</body-content>
<attribute>
<name>id</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>scope</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<tag>
<name>dynamic</name>
<tag-
![](/icons/70413class.gif)
>com.devsphere.articles.jspcache.DynamicTag</tag-
![](/icons/70413class.gif)
>
<body-content>empty</body-content>
<attribute>
<name>expr</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag></taglib>
TLD文件包含在Web应用描述符文件(web.xml)中
![](/icons/70413dou.gif)
这 5个文件同样包含
![](/icons/70413yi.gif)
个
![](/icons/70413chushi.gif)
参数指出cache是否可用
![](/icons/70413dou2.gif)
<?xml version="1.0" encoding="ISO-8859-1"?><web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd"
version="2.4">
<context-param>
<param-name>com.devsphere.articles.jspcache.enabled</param-name>
<param-value>true</param-value>
</context-param>
<jsp-config>
<taglib>
<taglib-uri>http://devsphere.com/articles/jspcache</taglib-uri>
<taglib-location>/WEB-INF/jspcache.tld</taglib-location>
</taglib>
</jsp-config></web-app>
理解<jc:cache>
工作机理 JSP容器为JSP页面中
![](/icons/70413de.gif)
每
![](/icons/70413yi.gif)
个<jc:cache>标签创建
![](/icons/70413yi.gif)
个CacheTag例子
![](/icons/70413dou.gif)
来对其处理
![](/icons/70413dou2.gif)
JSP容器负责
![](/icons/70413diaoyong.gif)
![](/icons/70413set.gif)
Jsp
![](/icons/70413kh.gif)
、
![](/icons/70413set.gif)
Parent
![](/icons/70413kh.gif)
和
![](/icons/70413set.gif)
JspBody
![](/icons/70413kh.gif)
思路方法
![](/icons/70413dou.gif)
这是CacheTag类从SimpleTagSupport继承而来
![](/icons/70413dou2.gif)
JSP容器同事还为所操作标签
![](/icons/70413de.gif)
每
![](/icons/70413yi.gif)
个属性
![](/icons/70413diaoyong.gif)
![](/icons/70413set.gif)
ter思路方法
![](/icons/70413dou2.gif)
SetId
![](/icons/70413kh.gif)
和
![](/icons/70413set.gif)
Scope
![](/icons/70413kh.gif)
思路方法存储属性值到私有域
![](/icons/70413dou.gif)
这个值已经用CacheTag
![](/icons/70413kh.gif)
构造
![](/icons/70413hanshu.gif)
用缺省值
![](/icons/70413chushi.gif)
化
package com.devsphere.articles.jspcache;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;import java.io.StringWriter;
public
![](/icons/70413class.gif)
CacheTag extends SimpleTagSupport {
public
![](/icons/70413static.gif)
final String CACHE_ENABLED
= "com.devsphere.articles.jspcache.enabled";
private String id;
private
![](/icons/70413int.gif)
scope;
private boolean cacheEnabled; public CacheTag
![](/icons/70413kh.gif)
{
id = null; scope = PageContext.APPLICATION_SCOPE;
} public void
![](/icons/70413set.gif)
Id(String id) {
this.id = id;
} public void
![](/icons/70413set.gif)
Scope(String scope) {
this.scope = JspUtils.checkScope(scope);
}
...}
![](/icons/70413set.gif)
Scope
![](/icons/70413kh.gif)
思路方法
![](/icons/70413diaoyong.gif)
JspUtils.checkScope
![](/icons/70413kh.gif)
来校验已经从String转换为
![](/icons/70413int.gif)
类型
![](/icons/70413de.gif)
scope
![](/icons/70413de.gif)
属性值
![](/icons/70413dou2.gif)
...public
![](/icons/70413class.gif)
JspUtils {
...
public
![](/icons/70413int.gif)
checkScope(String scope) {
![](/icons/70413if.gif)
("page".equalsIgnoreCase(scope))
![](/icons/70413return.gif)
PageContext.PAGE_SCOPE;
![](/icons/70413if.gif)
("request".equalsIgnoreCase(scope))
![](/icons/70413return.gif)
PageContext.REQUEST_SCOPE;
![](/icons/70413if.gif)
("session".equalsIgnoreCase(scope))
![](/icons/70413return.gif)
PageContext.SESSION_SCOPE;
![](/icons/70413if.gif)
("application".equalsIgnoreCase(scope))
![](/icons/70413return.gif)
PageContext.APPLICATION_SCOPE;
![](/icons/70413else.gif)
throw
![](/icons/70413new.gif)
IllegalArgumentException(
"Invalid scope: " + scope);
}}
![](/icons/70413yi.gif)
旦CacheTag例子准备对标签进行操作
![](/icons/70413dou.gif)
JSP容器
![](/icons/70413diaoyong.gif)
doTag
![](/icons/70413kh.gif)
思路方法
![](/icons/70413dou.gif)
用getJspContext
![](/icons/70413kh.gif)
来获得JSP context
![](/icons/70413dou2.gif)
这个对象被造型为PageContext,从而可以
![](/icons/70413diaoyong.gif)
getServletContext
![](/icons/70413kh.gif)
思路方法
![](/icons/70413dou2.gif)
servlet context用来获取
![](/icons/70413chushi.gif)
化参数
![](/icons/70413de.gif)
值
![](/icons/70413dou.gif)
这个值标明缓存Cache机制是否被启用
![](/icons/70413dou2.gif)
如果缓存Cache被启用
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
尝试使用id和scope属性值来获得缓存Cache页面片段
![](/icons/70413dou2.gif)
如果页面片段还没有被缓存Cache
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
使用getJspBody
![](/icons/70413kh.gif)
.invoke
![](/icons/70413kh.gif)
来执行由<jc:cache>和</jc:cache>封装
![](/icons/70413de.gif)
JSP代码
![](/icons/70413dou2.gif)
由JSP body产生
![](/icons/70413de.gif)
输出结果缓冲在StringWriter并且被toStirng
![](/icons/70413kh.gif)
思路方法获得
![](/icons/70413dou2.gif)
这样
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
![](/icons/70413diaoyong.gif)
JSP context
![](/icons/70413de.gif)
![](/icons/70413set.gif)
Attribute
![](/icons/70413kh.gif)
思路方法新建
![](/icons/70413yi.gif)
个JSP变量
![](/icons/70413dou.gif)
这个变量控制可能包含JSP表达式(${…})
![](/icons/70413de.gif)
缓存Cache内容
![](/icons/70413dou2.gif)
这些表达式在用jspContext.getOut
![](/icons/70413kh.gif)
.pr
![](/icons/70413int.gif)
![](/icons/70413kh.gif)
输出内容前
![](/icons/70413dou.gif)
被JspUtils.eval
![](/icons/70413kh.gif)
赋值
![](/icons/70413dou2.gif)
只有当缓存Cache被启用
![](/icons/70413de.gif)
时候
![](/icons/70413dou.gif)
这些行为才发生
![](/icons/70413dou2.gif)
否则
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
只是通过getJspBody
![](/icons/70413kh.gif)
.invoke(null)执行JSP body并且输出结果不被缓存Cache
![](/icons/70413dou2.gif)
...public
![](/icons/70413class.gif)
CacheTag extends SimpleTagSupport {
...
public void doTag
![](/icons/70413kh.gif)
throws JspException, IOException {
JspContext jspContext = getJspContext
![](/icons/70413kh.gif)
;
ServletContext application
= ((PageContext) jspContext).getServletContext
![](/icons/70413kh.gif)
;
String cacheEnabledParam
= application.getInitParameter(CACHE_ENABLED);
cacheEnabled = cacheEnabledParam != null
&& cacheEnabledParam.equals("true");
![](/icons/70413if.gif)
(cacheEnabled) {
String cachedOutput
= (String) jspContext.getAttribute(id, scope);
![](/icons/70413if.gif)
(cachedOutput
![](/icons/70413dd.gif)
null) {
StringWriter buffer =
![](/icons/70413new.gif)
StringWriter
![](/icons/70413kh.gif)
;
getJspBody
![](/icons/70413kh.gif)
.invoke(buffer);
cachedOutput = buffer.toString
![](/icons/70413kh.gif)
;
jspContext.
![](/icons/70413set.gif)
Attribute(id, cachedOutput, scope);
} String evaluatedOutput = (String) JspUtils.eval(
cachedOutput, String.
![](/icons/70413class.gif)
, jspContext);
jspContext.getOut
![](/icons/70413kh.gif)
.pr
![](/icons/70413int.gif)
(evaluatedOutput);
}
![](/icons/70413else.gif)
getJspBody
![](/icons/70413kh.gif)
.invoke(null);
}
...}
注意
![](/icons/70413yi.gif)
个单独
![](/icons/70413de.gif)
JspUtils.eval
![](/icons/70413kh.gif)
![](/icons/70413diaoyong.gif)
给所有
![](/icons/70413de.gif)
${…} 表达式赋值
![](/icons/70413dou2.gif)
![](/icons/70413yinwei.gif)
![](/icons/70413yi.gif)
个包含了大量
![](/icons/70413de.gif)
${…}结构
![](/icons/70413de.gif)
text也是
![](/icons/70413yi.gif)
个表达式
![](/icons/70413dou2.gif)
每
![](/icons/70413yi.gif)
个缓存Cache片段都可以被当作
![](/icons/70413yi.gif)
个复杂
![](/icons/70413de.gif)
JSP表达式来进行处理
IsCacheEnabled
![](/icons/70413kh.gif)
思路方法返回cacheEnabled
![](/icons/70413de.gif)
值
![](/icons/70413dou.gif)
这个值已经被doTag
![](/icons/70413kh.gif)
![](/icons/70413chushi.gif)
化
![](/icons/70413dou2.gif)
...public
![](/icons/70413class.gif)
CacheTag extends SimpleTagSupport {
... public boolean isCacheEnabled
![](/icons/70413kh.gif)
{
![](/icons/70413return.gif)
cacheEnabled;
}}
<jc:cache>标签允许页面开发者自主选择缓存Cache页面片段
![](/icons/70413de.gif)
ID
![](/icons/70413dou2.gif)
这使得缓存Cache
![](/icons/70413yi.gif)
个页面片段可以被多个JSP页面共享
![](/icons/70413dou.gif)
当需要重用JSP代码时
![](/icons/70413dou.gif)
这是很有用处
![](/icons/70413de.gif)
![](/icons/70413dou2.gif)
但是仍然需要
![](/icons/70413yi.gif)
些命名协议来避免可能
![](/icons/70413de.gif)
冲突
![](/icons/70413dou2.gif)
通过修改CacheTag类来在自动ID内部包含URL可以避免这种副作用
理解<jc:dynamic>在做什么 每
![](/icons/70413yi.gif)
个<jc:dynamic>被
![](/icons/70413yi.gif)
个DynamicTag类
![](/icons/70413de.gif)
例子处理
![](/icons/70413dou.gif)
![](/icons/70413set.gif)
Expr
![](/icons/70413kh.gif)
思路方法将expr属性值存储到
![](/icons/70413yi.gif)
个私有域
![](/icons/70413dou2.gif)
DoTag
![](/icons/70413kh.gif)
思路方法创建JSP表达式
![](/icons/70413dou.gif)
在expr属性值加上${前缀和}后缀
![](/icons/70413dou2.gif)
然后
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
使用findAncestorWithClass
![](/icons/70413kh.gif)
来查找含有<jc:dynamic>标签元素
![](/icons/70413de.gif)
<jc:cache>
![](/icons/70413de.gif)
CacheTag handler
![](/icons/70413dou2.gif)
如果没有查找到或者缓存Cache被禁用
![](/icons/70413dou.gif)
JSP表达式被JspUtils.eval
![](/icons/70413kh.gif)
赋值并且值被输出
![](/icons/70413dou2.gif)
否则
![](/icons/70413dou.gif)
doTag
![](/icons/70413kh.gif)
输出无值表达式
package com.devsphere.articles.jspcache;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
public
![](/icons/70413class.gif)
DynamicTag extends SimpleTagSupport {
private String expr;
public void
![](/icons/70413set.gif)
Expr(String expr) {
this.expr = expr;
} public void doTag
![](/icons/70413kh.gif)
throws JspException, IOException {
String output = "${" + expr + "}";
CacheTag ancestor = (CacheTag) findAncestorWithClass(
this, CacheTag.
![](/icons/70413class.gif)
);
![](/icons/70413if.gif)
(ancestor
![](/icons/70413dd.gif)
null || !ancestor.isCacheEnabled
![](/icons/70413kh.gif)
)
output = (String) JspUtils.eval(
output, String.
![](/icons/70413class.gif)
, getJspContext
![](/icons/70413kh.gif)
);
getJspContext
![](/icons/70413kh.gif)
.getOut
![](/icons/70413kh.gif)
.pr
![](/icons/70413int.gif)
(output);
}}
分析以上代码
![](/icons/70413dou.gif)
可以注意到<jc:cache>和<jc:dynamic>合作来实现
![](/icons/70413yi.gif)
个尽可能有效率
![](/icons/70413de.gif)
方案
![](/icons/70413dou2.gif)
如果缓存Cache可用
![](/icons/70413dou.gif)
页面片段和由<jc:dynamic>生成并被CacheTag赋值
![](/icons/70413de.gif)
JSP表达式
![](/icons/70413yi.gif)
起放入缓冲器
![](/icons/70413dou2.gif)
如果缓存Cache被禁用
![](/icons/70413dou.gif)
缓冲变得没有意义
![](/icons/70413dou.gif)
<jc:cache>只是执行其JSP body部分
![](/icons/70413dou.gif)
而让DynamicTag给JSP表达式赋值
![](/icons/70413dou2.gif)
禁用缓存Cache有时候是必要
![](/icons/70413de.gif)
![](/icons/70413dou.gif)
特别是在开发过程期间出现内容
![](/icons/70413de.gif)
改变和JSP页面被重新编译
![](/icons/70413de.gif)
时候
![](/icons/70413dou2.gif)
当然
![](/icons/70413dou.gif)
在开发完毕
![](/icons/70413de.gif)
成品环境中缓存Cache必须被启用
整理总结 内容缓存Cache是
![](/icons/70413yi.gif)
种非常易用
![](/icons/70413de.gif)
改善Web应用性能
![](/icons/70413de.gif)
思路方法
![](/icons/70413dou2.gif)
这篇文章集中讨论了使用JSP表达式语言来为每
![](/icons/70413yi.gif)
个用户或者请求定制缓存Cache内容
![](/icons/70413dou2.gif)
贯穿全文
![](/icons/70413de.gif)
简单介绍
![](/icons/70413de.gif)
标签库适合小型Web apps并且可以提升中等应用
![](/icons/70413de.gif)
性能
![](/icons/70413dou2.gif)
对于开发大型企业级应用
![](/icons/70413dou.gif)
则该考虑使用支持更好
![](/icons/70413de.gif)
缓存Cache机制
![](/icons/70413de.gif)
框架结构
![](/icons/70413dou.gif)
而不仅是使用JSP变量
![](/icons/70413dou2.gif)
但是了解基于EL API
![](/icons/70413de.gif)
定制技术无疑是不无裨益
![](/icons/70413de.gif)
TAG:
jsp
JSP