搜索|收藏|地图|订阅|图片|论坛|商城
  当前位置 :| 首页>软件>编程学院>Jsp>实例解析>

JSP 2.0下的动态内容缓存分析讲解

来源:matrix 编辑:若水 时间:2008-05-14

  
  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 class CacheTag extends SimpleTagSupport {
  public static final String CACHE_ENABLED
  = "com.devsphere.articles.jspcache.enabled";
  private String id;
  private int scope;
  private boolean cacheEnabled;  public CacheTag() {
  id = null;    scope = PageContext.APPLICATION_SCOPE;
  }  public void setId(String id) {
  this.id = id;
  }  public void setScope(String scope) {
  this.scope = JspUtils.checkScope(scope);
  }
  ...}
  
  setScope()方法调用JspUtils.checkScope()来校验已经从String转换为int类型的scope的属性值。
  ...public class JspUtils {
  ...
  public static int checkScope(String scope) {
  if ("page".equalsIgnoreCase(scope))
  return PageContext.PAGE_SCOPE;
  else if ("request".equalsIgnoreCase(scope))
  return PageContext.REQUEST_SCOPE;
  else if ("session".equalsIgnoreCase(scope))
  return PageContext.SESSION_SCOPE;
  else if ("application".equalsIgnoreCase(scope))
  return PageContext.APPLICATION_SCOPE;
  else
  throw new IllegalArgumentException(
  "Invalid scope: " + scope);
  }}
  
  一旦CacheTag实例准备对标签进行操作,JSP容器调用doTag()方法,用getJspContext()来获得JSP context。这个对象被造型为PageContext,从而可以调用getServletContext()方法。servlet context用来获取初始化参数的值,这个值标明缓存机制是否被启用。如果缓存被启用,doTag()尝试使用id和scope属性值来获得缓存页面片段。如果页面片段还没有被缓存,doTag()使用getJspBody().invoke()来执行由<jc:cache>和</jc:cache>封装的JSP代码。由JSP body产生的输出结果缓冲在StringWriter并且被toStirng()方法获得。这样,doTag()调用JSP context的setAttribute()方法新建一个JSP变量,这个变量控制可能包含JSP表达式(${…})的缓存内容。这些表达式在用jspContext.getOut().print()输出内容前,被JspUtils.eval()赋值。只有当缓存被启用的时候,这些行为才发生。否则,doTag()只是通过getJspBody().invoke(null)执行JSP body并且输出结果不被缓存。

  ...public class CacheTag extends SimpleTagSupport {
  ...
  public void doTag() throws JspException, IOException {
  JspContext jspContext = getJspContext();
  ServletContext application
  = ((PageContext) jspContext).getServletContext();
  String cacheEnabledParam
  = application.getInitParameter(CACHE_ENABLED);
  cacheEnabled = cacheEnabledParam != null
  && cacheEnabledParam.equals("true");
  if (cacheEnabled) {
  String cachedOutput
  = (String) jspContext.getAttribute(id, scope);
  if (cachedOutput == null) {
  StringWriter buffer = new StringWriter();
  getJspBody().invoke(buffer);
  cachedOutput = buffer.toString();
  jspContext.setAttribute(id, cachedOutput, scope);
  }      String evaluatedOutput = (String) JspUtils.eval(
  cachedOutput, String.class, jspContext);
  jspContext.getOut().print(evaluatedOutput);
  } else
  getJspBody().invoke(null);
  }
  ...}
  
  注意一个单独的JspUtils.eval()调用给所有的${…} 表达式赋值。因为一个包含了大量的${…}结构的text也是一个表达式。每一个缓存片段都可以被当作一个复杂的JSP表达式来进行处理。
  
  IsCacheEnabled()方法返回cacheEnabled的值,这个值已经被doTag()初始化。
  ...public class CacheTag extends SimpleTagSupport {
  ...  public boolean isCacheEnabled() {
  return cacheEnabled;
  }}
  
  <jc:cache>标签允许页面开发者自主选择缓存页面片段的ID。这使得缓存一个页面片段可以被多个JSP页面共享,当需要重用JSP代码时,这是很有用处的。但是仍然需要一些命名协议来避免可能的冲突。通过修改CacheTag类来在自动ID内部包含URL可以避免这种副作用。
  
  理解<jc:dynamic>在做什么
  
  每一个<jc:dynamic>被一个DynamicTag类的实例处理,setExpr()方法将expr属性值存储到一个私有域。DoTag()方法创建JSP表达式,在expr属性值加上${前缀和}后缀。然后,doTag()使用findAncestorWithClass()来查找含有<jc:dynamic>标签元素的<jc:cache>的CacheTag handler。如果没有查找到或者缓存被禁用,JSP表达式被JspUtils.eval()赋值并且值被输出。否则,doTag()输出无值表达式。
  
  package com.devsphere.articles.jspcache;
  import javax.servlet.jsp.JspException;
  import javax.servlet.jsp.tagext.SimpleTagSupport;
  import java.io.IOException;
  public class DynamicTag extends SimpleTagSupport {
  private String expr;
  public void setExpr(String expr) {
  this.expr = expr;
  }  public void doTag() throws JspException, IOException {
最新评论共有 0 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?