仓酷云

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 574|回复: 12
打印 上一主题 下一主题

[学习教程] JAVA教程之JSP 2.0下的静态内容缓存剖析解说

[复制链接]
山那边是海 该用户已被删除
跳转到指定楼层
楼主
发表于 2015-1-18 11:18:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
没有那个大公司会傻了吧唧用.net开发大型项目,开发了,那等于自己一半的生命线被微软握着呢。而.net不行,限制在window系统,又是捆绑,鄙视微软之!在Web使用中,内容缓存是最一般的优化手艺之一,而且可以很简单地完成。比方,可使用一个自界说地JSP标签――我们将之定名为<jc:cache>――由<jc:cache>和</jc:cache>将每个必要被缓存的页面片断封装起来。任何自界说标签能够把持它所包括部分(也即事后封装的页面片断)在什么时候实行,而且静态输入了局能够被捕捉。<jc:cache>标签使得JSP容器(比方Tomcat)只天生内容一次,作为使用程序局限内的JSP变量,来存储每个缓存片断。每次JSP页面被实行时,自界说标签将缓存页面片断载进而无需再次实行JSP代码来天生输入了局。作为Jakarta工程的一个部分,标签库的开辟利用了这项手艺。当被缓存内容无需被每个用户大概哀求所定制的时分,它事情的非常优秀。
  
  这篇文章对下面形貌的手艺做了改善,经由过程利用JSP2.0表达式言语(EL),同意JSP页面为每个哀求和用户定制缓存内容。缓存页面片断能够包括未被JSP容器赋值的JSP表达式,在每次页面被实行时,由自界说标签来断定这些表达式的值。因而,静态内容的创建被最优化,可是缓存片断能够含有部分由每个哀求利用本机JSP表达式言语发生的内容。经由过程JSP2.0ELAPI的匡助,Java开辟者能够用表达式言语来使之成为大概。
  
  内容缓存VS数据缓存
  
  内容缓存不是独一的选择。比方,从数据库中提取的数据一样能够被缓存。现实上,因为存储的信息中不包括HTMLmarkup,和请求较少的内存,数据缓存大概加倍高效力。但是在良多情形下,内存缓存更简单完成。假定在某个案例总,一个使用由大批事件对象,占用主要的CPU资本,发生庞大的数据,而且用JSP页面来出现这些数据。事情统统优秀,直到某天俄然地服务器的负载增添,必要一个告急办理计划。这时候在事件对象和出现表达层之间创建一个缓存层,时一个十分不错和无效的计划。可是必需十分疾速和流利地修正缓存静态内容的JSP页面。相对复杂的JSP页面编纂,使用程序的营业逻辑变更一般请求更多的事情量和测试;别的,假如一个页面从多个复合源聚合信息时,Web层唯一大批的改动。成绩在于,当缓存信息变得得到时效时,缓存空间必要被开释,而事件对象应当晓得什么时候产生这类情形。但是,选择完成内容缓存仍是数据缓存,大概其他的优化手艺,有良多不能不思索的要素,偶然是所开辟的程序所特别请求的。
  
  数据缓存和内容缓存没有需要相互排挤,它们能够一同利用。比方,在数据库驱动的使用中;从数据库中提掏出来的数据,和出现该数据的HTML分离被缓存起来。这与利用JSP及时天生的模板有些类似。这篇文章中会商的基于ELAPI手艺申明怎样利用JSPEL来将数据载进到出现模板中。
  
  利用JSP变量缓存静态内容
  
  每当完成一个缓存机制是,都必要一个存储缓存对象的办法,在这篇文章中触及的是String范例的对象。一种选择是利用一个对象――缓存框架布局,大概利用Javamaps来完成自界说的缓存计划。JSP已具有了称为“scopedattributes”或“JSPvariables”来供应ID――object映照,这恰是缓存机制所必要的。关于利用page大概requestscope,这是没成心义的,而在使用局限内,这是一个很好的存储缓存内容的地位,由于它被一切的用户和页面共享。当每个用户必要独自缓存时,Sessionscope也能够被利用,但这不是很无效率。JSTL标签库能够被是与谁人来缓存内容,经由过程利用JSP变量正以下例所示:
  
  <%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%><c:iftest="${emptycachedFragment}">
  <c:setvar="cachedFragment"scope="application">
  ...
  </c:set></c:if>
  
  缓存页面片断用以下语句输入了局:
  ${applicationScope.cachedFragment}
  
  当缓存片断必要被每个哀求所定制的时分,究竟产生了甚么?比方,假如但愿包括一个计数器,必要缓存两个片断:
  <%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%><c:iftest="${sessionScope.counter==null}">  <c:setvar="counter"scope="session"value="0"/></c:if><c:setvar="counter"value="${counter+1}"scope="session"/><c:iftest="${emptycachedFragment1}">
  <c:setvar="cachedFragment1"scope="application">
  ...
  </c:set></c:if><c:iftest="${emptycachedFragment2}">
  <c:setvar="cachedFragment2"scope="application">
  ...
  </c:set></c:if>
  
  可使用上面语句输入缓存内容:
  ${cachedFragment1}${counter}${cachedFragment2}
  
  经由过程专门的标签库的匡助,必要定制的页面片断的缓存变得非常简单了。下面已说起,缓存内容能够被入手下手标签(<jc:cache>)和开头标签(</jc:cache>)封装起来。而每个定制可使用另外一个标签(<jc:dynamicexpr="..."/>)输入一个JSP表达式(${...})来体现。静态内容用JSP表达式缓存并在每次缓存内容被输入时赋值。鄙人面的部分能够看到这是怎样完成的。Counter.jsp缓存了一个包括计数器的页面片断,当每次用户革新这个页面的时分计数器会主动+1。
  <%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%><%@taglibprefix="jc"uri="http://devsphere.com/articles/jspcache"%><c:iftest="${sessionScope.counter==null}">
  <c:setvar="counter"scope="session"value="0"/></c:if><c:setvar="counter"value="${counter+1}"scope="session"/><jc:cacheid="cachedFragmentWithCounter">
  ...<jc:dynamicexpr="sessionScope.counter"/>
  ...</jc:cache>
  
  JSP变量易于利用,关于复杂的Webapps,这是一个不错的内容缓存计划。但是,假如使用程序发生大批的静态内容,没有对缓存巨细的把持无疑是一个成绩。一种公用的缓存框架布局可以供应一个加倍无力的计划,同意对缓存的监督,限定缓存巨细,把持缓存战略,等等……
  
  利用JSP2.0表达式言语API
  
  JSP容器(比方Tomcat)对使用ELAPI的JSP页面中的表达式予以赋值,而且能够被Java代码所利用。这同意在Web页面外使用JSPEL作开辟,比方,对XML文件、基于文本的资本和自界说剧本。当必要把持什么时候对Web页面中的表达式举行赋值大概誊写与之相干的表达式时,ELAPI一样是有效的。比方,缓存页面片断能够包括自界说JSP表达式,而且当每次缓存内容被输入时,ELAPI将用来给这些表达式赋值大概从头赋值。
  
  文章供应了一个例子程序(拜见文末资本部分),这个使用程序包括了一个Java类(JspUtils)和类中包括一个办法eval(),这个办法有三个参数:JSP表达式、表达式的希冀范例和一个JSPcontext对象。Eval()办法从JSPcontext中获得ExpressionEvaluator而且挪用evaluate()办法,经由过程表达式、表达式的希冀范例、和一个从JSPcongtext中取得的变量。JspUtils.eval()办法前往表达式的值。
  packagecom.devsphere.articles.jspcache;
  importjavax.servlet.jsp.JspContext;
  importjavax.servlet.jsp.JspException;
  importjavax.servlet.jsp.PageContext;
  importjavax.servlet.jsp.el.ELException;
  importjavax.servlet.jsp.el.ExpressionEvaluator;
  importjava.io.IOException;publicclassJspUtils{
  publicstaticObjecteval(
  Stringexpr,Classtype,JspContextjspContext)
  throwsJspException{
  try{
  if(expr.indexOf("${")==-1)
  returnexpr;
  ExpressionEvaluatorevaluator
  =jspContext.getExpressionEvaluator();
  returnevaluator.evaluate(expr,type,
  jspContext.getVariableResolver(),null);
  }catch(ELExceptione){
  thrownewJspException(e);
  }
  }
  ...}
  
  注重:JspUtils.eval()次要封装了尺度的ExpressionEvaluator。假如expr不包括${,JSPELAPI不被挪用,由于没有JSP表达式。

创立标签库形貌符(TLD)文件
  
  JSP标签库必要一个标签库形貌符(TLD)文件来自界说标签的定名,它们的属性,和操纵该标签的Java类。jspcache.tld形貌了两个自界说标签,<jc:cache>具有两个属性:缓存页面片断的id和JSPscope―JSP页面总必要被贮存的内容局限。<jc:dynamic>只要一个属性,即JSP表达式必需在每次缓存片断被输入时被赋值。TLD文件将这两个自界说标签映照到CacheTag和DynamicTag类,以下所示:
  <?xmlversion="1.0"encoding="UTF-8"?><taglibxmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-jsptaglibrary_2_0.xsd"
  version="2.0">
  <tlib-version>1.0</tlib-version>
  <short-name>jc</short-name>
  <uri>http://devsphere.com/articles/jspcache</uri>
  <tag>
  <name>cache</name>
  <tag-class>com.devsphere.articles.jspcache.CacheTag</tag-class>
  <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-class>com.devsphere.articles.jspcache.DynamicTag</tag-class>
  <body-content>empty</body-content>
  <attribute>
  <name>expr</name>
  <required>true</required>
  <rtexprvalue>false</rtexprvalue>
  </attribute>
  </tag></taglib>
  
  TLD文件包括在Web使用形貌符文件(web.xml)中,这五个文件一样包括一个初始参数指出cache是不是可用。
  <?xmlversion="1.0"encoding="ISO-8859-1"?><web-appxmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2eeweb-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页面中的每个<jc:cache>标签创立一个CacheTag实例,来对其处置。JSP容器卖力挪用setJsp()、setParent()和setJspBody()办法,这是CacheTag类从SimpleTagSupport承继而来。JSP容器同事还为所操纵标签的每个属性挪用setter办法。SetId()和setScope()办法存储属性值到公有域,这个值已用CacheTag()机关函数用缺省值初始化。
  
  packagecom.devsphere.articles.jspcache;
  importjavax.servlet.ServletContext;
  importjavax.servlet.jsp.JspContext;
  importjavax.servlet.jsp.JspException;
  importjavax.servlet.jsp.PageContext;
  importjavax.servlet.jsp.tagext.SimpleTagSupport;
  importjava.io.IOException;importjava.io.StringWriter;
  publicclassCacheTagextendsSimpleTagSupport{
  publicstaticfinalStringCACHE_ENABLED
  ="com.devsphere.articles.jspcache.enabled";
  privateStringid;
  privateintscope;
  privatebooleancacheEnabled;  publicCacheTag(){
  id=null;    scope=PageContext.APPLICATION_SCOPE;
  }  publicvoidsetId(Stringid){
  this.id=id;
  }  publicvoidsetScope(Stringscope){
  this.scope=JspUtils.checkScope(scope);
  }
  ...}
  
  setScope()办法挪用JspUtils.checkScope()来校验已从String转换为int范例的scope的属性值。
  ...publicclassJspUtils{
  ...
  publicstaticintcheckScope(Stringscope){
  if("page".equalsIgnoreCase(scope))
  returnPageContext.PAGE_SCOPE;
  elseif("request".equalsIgnoreCase(scope))
  returnPageContext.REQUEST_SCOPE;
  elseif("session".equalsIgnoreCase(scope))
  returnPageContext.SESSION_SCOPE;
  elseif("application".equalsIgnoreCase(scope))
  returnPageContext.APPLICATION_SCOPE;
  else
  thrownewIllegalArgumentException(
  "Invalidscope:"+scope);
  }}
  
  一旦CacheTag实例筹办对标签举行操纵,JSP容器挪用doTag()办法,用getJspContext()来取得JSPcontext。这个对象被外型为PageContext,从而能够挪用getServletContext()办法。servletcontext用来猎取初始化参数的值,这个值标明缓存机制是不是被启用。假如缓存被启用,doTag()实验利用id和scope属性值来取得缓存页面片断。假如页面片断还没有被缓存,doTag()利用getJspBody().invoke()来实行由<jc:cache>和</jc:cache>封装的JSP代码。由JSPbody发生的输入了局缓冲在StringWriter而且被toStirng()办法取得。如许,doTag()挪用JSPcontext的setAttribute()办法新建一个JSP变量,这个变量把持大概包括JSP表达式(${…})的缓存内容。这些表达式在用jspContext.getOut().print()输入内容前,被JspUtils.eval()赋值。只要当缓存被启用的时分,这些举动才产生。不然,doTag()只是经由过程getJspBody().invoke(null)实行JSPbody而且输入了局不被缓存。

  ...publicclassCacheTagextendsSimpleTagSupport{
  ...
  publicvoiddoTag()throwsJspException,IOException{
  JspContextjspContext=getJspContext();
  ServletContextapplication
  =((PageContext)jspContext).getServletContext();
  StringcacheEnabledParam
  =application.getInitParameter(CACHE_ENABLED);
  cacheEnabled=cacheEnabledParam!=null
  &&cacheEnabledParam.equals("true");
  if(cacheEnabled){
  StringcachedOutput
  =(String)jspContext.getAttribute(id,scope);
  if(cachedOutput==null){
  StringWriterbuffer=newStringWriter();
  getJspBody().invoke(buffer);
  cachedOutput=buffer.toString();
  jspContext.setAttribute(id,cachedOutput,scope);
  }      StringevaluatedOutput=(String)JspUtils.eval(
  cachedOutput,String.class,jspContext);
  jspContext.getOut().print(evaluatedOutput);
  }else
  getJspBody().invoke(null);
  }
  ...}
  
  注重一个独自的JspUtils.eval()挪用给一切的${…}表达式赋值。由于一个包括了大批的${…}布局的text也是一个表达式。每个缓存片断都能够被看成一个庞大的JSP表达式来举行处置。
  
  IsCacheEnabled()办法前往cacheEnabled的值,这个值已被doTag()初始化。
  ...publicclassCacheTagextendsSimpleTagSupport{
  ...  publicbooleanisCacheEnabled(){
  returncacheEnabled;
  }}
  
  <jc:cache>标签同意页面开辟者自立选择缓存页面片断的ID。这使得缓存一个页面片断能够被多个JSP页面共享,当必要重用JSP代码时,这是很有效处的。可是仍旧必要一些定名协定来制止大概的抵触。经由过程修正CacheTag类来在主动ID外部包括URL能够制止这类反作用。
  
  了解<jc:dynamic>在做甚么
  
  每个<jc:dynamic>被一个DynamicTag类的实例处置,setExpr()办法将expr属性值存储到一个公有域。DoTag()办法创立JSP表达式,在expr属性值加上${前缀和}后缀。然后,doTag()利用findAncestorWithClass()来查找含有<jc:dynamic>标签元素的<jc:cache>的CacheTaghandler。假如没有查找到大概缓存被禁用,JSP表达式被JspUtils.eval()赋值而且值被输入。不然,doTag()输入无值表达式。
  
  packagecom.devsphere.articles.jspcache;
  importjavax.servlet.jsp.JspException;
  importjavax.servlet.jsp.tagext.SimpleTagSupport;
  importjava.io.IOException;
  publicclassDynamicTagextendsSimpleTagSupport{
  privateStringexpr;
  publicvoidsetExpr(Stringexpr){
  this.expr=expr;
  }  publicvoiddoTag()throwsJspException,IOException{
  Stringoutput="${"+expr+"}";
  CacheTagancestor=(CacheTag)findAncestorWithClass(
  this,CacheTag.class);
  if(ancestor==null||!ancestor.isCacheEnabled())
  output=(String)JspUtils.eval(
  output,String.class,getJspContext());
  getJspContext().getOut().print(output);
  }}
  
  剖析以上代码,能够注重到<jc:cache>和<jc:dynamic>互助来完成一个尽量无效率的计划。假如缓存可用,页面片断和由<jc:dynamic>天生并被CacheTag赋值的JSP表达式一同放进缓冲器。假如缓存被禁用,缓冲变得没成心义,<jc:cache>只是实行其JSPbody部分,而让DynamicTag给JSP表达式赋值。禁用缓存偶然候是需要的,出格是在开辟历程时代呈现内容的改动和JSP页面被从头编译的时分。固然,在开辟终了的制品情况中缓存必需被启用。
  
  总结
  
  内容缓存是一种十分易用的改良Web使用功能的办法。这篇文章会合会商了利用JSP表达式言语来为每个用户大概哀求定制缓存内容。贯串全文的复杂先容的标签库合适小型Webapps而且能够提拔中等使用的功能。关于开辟年夜型企业级使用,则该思索利用撑持更好的缓存机制的框架布局,而不但是利用JSP变量。可是懂得基于ELAPI的定制手艺无疑是不无裨益的。

手机用到的是用j2me所编出来的小程序。
爱飞 该用户已被删除
沙发
发表于 2015-1-20 19:58:46 | 只看该作者
Java是一个纯的面向对象的程序设计语言,它继承了 C++语言面向对象技术的核心。Java舍弃了C ++语言中容易引起错误的指针(以引用取代)、运算符重载(operator overloading)
莫相离 该用户已被删除
板凳
发表于 2015-1-25 07:27:16 | 只看该作者
是一种使网页(Web Page)由静态(Static)转变为动态(Dynamic)的语言
蒙在股里 该用户已被删除
地板
发表于 2015-1-25 18:45:12 | 只看该作者
是一种语言,用以产生「小应用程序(Applet(s))
冷月葬花魂 该用户已被删除
5#
发表于 2015-1-25 22:50:16 | 只看该作者
你可以去承接一些项目做了,一开始可能有些困难,可是你有技术积累,又考虑周全,接下项目来可以迅速作完,相信大家以后都会来找你的,所以Money就哗啦啦的。。。。。。
精灵巫婆 该用户已被删除
6#
发表于 2015-2-4 07:14:17 | 只看该作者
是一种使网页(Web Page)由静态(Static)转变为动态(Dynamic)的语言
海妖 该用户已被删除
7#
发表于 2015-2-9 18:38:06 | 只看该作者
是一种为 Internet发展的计算机语言
柔情似水 该用户已被删除
8#
发表于 2015-2-27 16:26:17 | 只看该作者
另外编写和运行Java程序需要JDK(包括JRE),在sun的官方网站上有下载,thinking in java第三版用的JDK版本是1.4,现在流行的版本1.5(sun称作J2SE 5.0,汗),不过听说Bruce的TIJ第四版国外已经出来了,是专门为J2SE 5.0而写的。
深爱那片海 该用户已被删除
9#
发表于 2015-3-1 09:13:34 | 只看该作者
其实说这种话的人就如当年小日本号称“三个月拿下中国”一样大言不惭。不是Tomjava泼你冷水,你现在只是学到了Java的骨架,却还没有学到Java的精髓。接下来你得研究设计模式了。
若天明 该用户已被删除
10#
发表于 2015-3-3 19:39:58 | 只看该作者
Java 编程语言的风格十分接近C、C++语言。
飘飘悠悠 该用户已被删除
11#
发表于 2015-3-6 16:45:10 | 只看该作者
你快去找一份Java的编程工作来做吧(如果是在校学生可以去做兼职啊),在实践中提高自己,那才是最快的。不过你得祈祷在公司里碰到一个高手,而且他 还愿意不厌其烦地教你,这样好象有点难哦!还有一个办法就是读开放源码的程序了。我们知道开放源码大都出自高手,他们设计合理,考虑周到,再加上有广大的程序员参与,代码的价值自然是字字珠叽,铿锵有力(对不起,偶最近《金装四大才子》看多了)。
飘灵儿 该用户已被删除
12#
发表于 2015-3-13 04:10:47 | 只看该作者
是一种简化的C++语言 是一种安全的语言,具有阻绝计算机病毒传输的功能
再见西城 该用户已被删除
13#
发表于 2015-3-20 12:30:16 | 只看该作者
你现在最缺的是实际的工作经验,而不是书本上那些凭空想出来的程序。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|仓酷云 鄂ICP备14007578号-2

GMT+8, 2024-11-15 05:26

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表