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

2016-02-19 14:00 5 1 收藏

图老师设计创意栏目是一个分享最好最实用的教程的社区,我们拥有最用心的各种教程,今天就给大家分享JSP 2.0下的动态内容缓存分析讲解的教程,热爱PS的朋友们快点看过来吧!

【 tulaoshi.com - Web开发 】

在Web应用中,内容缓存是最普通的优化技术之一,并且能够很容易地实现。例如,可以使用一个自定义地JSP标签——我们将之命名为<jc:cache>——由<jc:cache>和</jc:cache>将每一个需要被缓存的页面片段封装起来。任何自定义标签可以控制它所包含部分 (也即预先封装的页面片段)在何时执行,并且动态输出结果可以被捕获。<jc:cache>标签使得JSP容器(例如Tomcat)只生成内容一次,作为应用程序范围内的JSP变量,来存储每一个缓存片段。每次JSP页面被执行时,自定义标签将缓存页面片段载入而无需再次执行JSP代码来生成输出结果。作为Jakarta工程的一个部分,标签库的开发使用了这项技术。当被缓存内容无需被每一个用户或者请求所定制的时候,它工作的十分良好。
  
  这篇文章对上面描述的技术做了改进,通过使用JSP 2.0表达式语言(EL),允许JSP页面为每一个请求和用户定制缓存内容。缓存页面片段可以包含未被JSP容器赋值的JSP表达式,在每一次页面被执行时,由自定义标签来确定这些表达式的值。因此,动态内容的建立被最优化,但是缓存片段可以含有部分由每一个请求使用本机JSP表达式语言产生的内容。通过JSP 2.0 EL API的帮助,Java开发者可以用表达式语言来使之成为可能。
  
  
  
  内容缓存不是唯一的选择。例如, 从数据库中提取的数据同样可以被缓存。事实上,由于存储的信息中不包含HTML markup,以及要求较少的内存,数据缓存可能更加高效率。然而在很多情况下,内存缓存更容易实现。假设在某个案例总,一个应用由大量事务对象,占用重要的CPU资源,产生复杂的数据,并且用JSP页面来呈现这些数据。工作一切良好,直到某天突然地服务器的负载增加,需要一个紧急解决方案。这时在事务对象和呈现表达层之间建立一个缓存层,时一个非常不错和有效的方案。但是必须非常快速和流畅地修改缓存动态内容的JSP页面。相对于简单的JSP页面编辑,应用程序的业务逻辑变化通常要求更多的工作量和测试;另外,如果一个页面从多个复合源聚合信息时,Web层仅有少量的改变。问题在于,当缓存信息变得失去时效时,缓存空间需要被释放,而事务对象应该知道何时发生这种情况。然而,选择实现内容缓存还是数据缓存,或者其他的优化技术,有很多不得不考虑的因素,有时是所开发的程序所特殊要求的。
  
  数据缓存和内容缓存没有必要互相排斥,它们可以一起使用。例如,在数据库驱动的应用中;从数据库中提取出来的数据,和呈现该数据的HTML分别被缓存起来。这与使用JSP实时生成的模板有些相似。这篇文章中讨论的基于EL API技术说明如何使用JSP EL来将数据载入到呈现模板中。
  
  
  
  每当实现一个缓存机制是,都需要一个存储缓存对象的方法,在这篇文章中涉及的是String类型的对象。 一种选择是使用一个对象——缓存框架结构,或者使用Java maps来实现自定义的缓存方案。JSP已经拥有了称为“scoped attributes”或“JSP variables”来提供ID——object映射,这正是缓存机制所需要的。对于使用page或者request scope,这是没有意义的,而在应用范围内,这是一个很好的存储缓存内容的位置, 因为它被所有的用户和页面共享。当每一个用户需要单独缓存时,Session scope也可以被使用,但这不是很有效率。JSTL标签库可以被是与那个来缓存内容,通过使用JSP变量正如下例所示:
  
  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:if test="${empty cachedFragment}">
  <c:set var="cachedFragment" scope="application">
  ...
  </c:set></c:if>
  
  缓存页面片段用下列语句输出结果:
  ${applicationScope.cachedFragment}
  
  当缓存片段需要被每一个请求所定制的时候,到底发生了什么?例如,如果希望包含一个计数器,需要缓存两个片段:
  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><c:if test="${sessionScope.counter == null}">  <c:set var="counter" scope="session" value="0"/></c:if><c:set var="counter" value="${counter+1}" scope="session"/><c:if test="${empty cachedFragment1}">
  <c:set var="cachedFragment1" scope="application">
  ...
  </c:set></c:if><c:if test="${empty cachedFragment2}">
  <c:set var="cachedFragment2" scope="application">
  ...
  </c:set></c:if>
  
  可以使用下面语句输出缓存内容:
  ${cachedFragment1} ${counter} ${cachedFragment2}
  
  通过专门的标签库的帮助,需要定制的页面片段的缓存变得异常容易了。上面已经提及,缓存内容可以被开始标签(<jc:cache>)和结尾标签(</jc:cache>)封装起来。而每一个定制可以使用另一个标签(<jc:dynamic expr="..."/>)输出一个JSP表达式(${...})来表现。动态内容用JSP表达式缓存并在每一次缓存内容被输出时赋值。在下面的部分可以看到这是如何实现的。Counter.jsp缓存了一个包含计数器的页面片段,当每一次用户刷新这个页面的时候计数器会自动+1。
  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ taglib prefix="jc" uri="http://devsphere.com/articles/jspcache" %><c:if test="${sessionScope.counter == null}">
  <c:set var="counter" scop

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/webkaifa/)<body-content>empty</body-content>
  <attribute>
  <name>expr</name>
  <required>true</required>
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  </tag></taglib>
  
  TLD文件包含在Web应用描述符文件(web.xml)中,这五个文件同样包含一个初始参数指出cache是否可用。
  <?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>
  
  
  
  JSP容器为JSP页面中的每一个<jc:cache>标签创建一个CacheTag实例,来对其处理。JSP容器负责调用setJsp()、setParent()和setJspBody()方法,这是CacheTag类从SimpleTagSupport继承而来。JSP容器同事还为所操作标签的每一个属性调用setter方法。SetId()和setScope()方法存储属性值到私有域,这个值已经用CacheTag()构造函数用缺省值初始化。
  
  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产生的输出结果缓冲在Str

期间出现内容的改变和JSP页面被重新编译的时候。当然,在开发完毕的成品环境中缓存必须被启用。
  
  
  
  内容缓存是一种非常易用的改善Web应用性能的方法。这篇文章集中讨论了使用JSP表达式语言来为每一个用户或者请求定制缓存内容。贯穿全文的简单介绍的标签库适合小型Web apps并且可以提升中等应用的性能。对于开发大型企业级应用,则该考虑使用支持更好的缓存机制的框架结构,而不仅是使用JSP变量。但是了解基于EL API的定制技术无疑是不无裨益的。

来源:http://www.tulaoshi.com/n/20160219/1605953.html

延伸阅读
启程动态数组V2.0 作者:黄建雄 下载源代码 简介 大量数据的管理是很多程序员的心病,很难找到一个速度快、效率高、支持超大规模数据的表,在1.0版本的基础上,启程花血本写下了这个强化了数据插入与删除的修正版,启程动态数组是一个功能强大的列表形数据管理链...
标签: Web开发
Servlet三个要素: 1.必须继承自HttpServlet 2.必须实现doGet()或者doPost() 3.必须在web.xml中配置Servlet servlet servlet-name /servlet-name servlet-class /servlet-class /servlet servlet-mapping servlet-name /servlet-name url-pattern /url-pattern /servelt-mapping HttpServeltRrequest:请求对象 getParameter():获得...
标签: Java JAVA基础
  1, 使用java提供的方法,在jsp或者servlet中都可以 <% response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires", 0); % 2, 使用HTML标记,如下面: <HEAD <META HTTP-EQUIV="Pragma&...
标签: Web开发
ZZzzz~ may wind Iframe src="/URL" width="x" height="x" scrolling="[OPTION]" frameborder="x"/iframe src:文件的路径,既可是HTML文件,也可以是文本、ASP等; width、height:"画中画"区域的宽与高; scrolling:当SRC的指定的HTML文件在指定的区域不显不完时,滚动选项,如果设置为NO,则不出现滚动条;如...
标签: Java JAVA基础
  jsp:useBean Action 的使用 一、 语法: <jsp:useBean id="beanInstanceName" scope="page|request|session|application" { class="package.class" | type="package.class" | class="package.class" type="package.class" | beanName="{package.class | <...

经验教程

52

收藏

11
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部