web项目中想在tomcat启动加载web时,就自动缓存上数据库中的某些“公用大数据”,减少对数据库的频繁访问,想通过Ehcache实现缓存,tomcat启动时的自加载用监听器来实现。
首先介绍下Ehcache
Ehcache是来sourceforge(http://ehcache.sourceforge.net/)的开源项目,是纯Java实现的简单、快速的Cache组件。可以对页面、对象、数据进行缓存,支持集群/分布式缓存。如果整合Spring、Hibernate也非常的简单,Spring对Ehcache的支持也非常好。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分布式的Cache,可以作为Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速度。使用S2SH开发网站,网站首页需要展示的数据多,访问量大。如果不做处理,则频繁的查询数据库,结果是页面显示的慢,服务器、数据库不堪重负。如果网站页面所展示的数据的更新不是特别频繁,想提高页面显示的速度,减轻服务器的负担,此时应该考虑使用缓存。
关于ehcache的缓存配置可参照Ehcache缓存配置,ehcache的创建和使用参照 http://sishuok.com/forum/posts/list/315.html。
网上关于ehcache的资料好多都是ehcache的一个实例module,即页面缓存,考虑到项目相关性,及了解ehcache原理的目的,尝试实现这个页面缓存。
过程很曲折,但都一一解决,现在梳理下整个步骤:
Tomcat 的webapps下新建个test目录,再建一个WEB-INF、WEB-INF/lib、WEB-INF/classes目录;
下载最新的ehcache-web包,然后将包中的ehcache-web-2.0.4.jar、ehcache-core-2.4.6.jar、slf4j-api-1.6.1.jar放入lib目录中;(注意,这三个包一个不能少!!!)
配置web.xml
<?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 http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<filter>
<filter-name>SimplePageCachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SimplePageCachingFilter</filter-name>
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>test.jsp</welcome-file>
</welcome-file-list>
</web-app>
使用SimplePageCachingFilter过滤类(继承CachingFilter)来实现对名为SimplePageCachingFilter的过滤器,这个过滤器拦截/test.jsp页面请求,也就是对该页面进行缓存。
配置ehcache.xml,这个文件要放到src目录下(编译后会在classes目录下)!
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<cache name="SimplePageCachingFilter" maxElementsInMemory="10000" eternal="false"
overflowToDisk="false" timeToIdleSeconds="300" timeToLiveSeconds="60"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
该缓存的有效生存时间是60秒,60秒后缓存失效,但不重新读,直到再有该页面请求,才重新读取到缓存中。
测试:test.jsp
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<HTML>
<HEAD>
<title>test</title>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<%
Date d=new Date();
System.out.println("execute test.jsp:"+d);
out.println(d);
%>
</HEAD>
<body>
</body>
</HTML>
该页面打印出页面被请求时的时间。
第一次访问test.jsp后的1分钟内,再次访问时的界面是不变,即tomcat返回的是缓存中的test.jsp。一分钟后再次访问时“tomcat”(通过SimplePageCachingFilter过滤器)重新读取test.jsp并放入缓存。tomcat输出结果为:
以上内容还参考了:
ehcache介绍 http://raychase.iteye.com/blog/1545906
http://blog.youkuaiyun.com/jingmaoxiaoqiang/article/details/9737647
http://blog.sina.com.cn/s/blog_46d5caa40100ka9z.html
http://blog.sina.com.cn/s/blog_56fd58ab0100w0pl.html
jsp从数据库取数据 http://happysoul.iteye.com/blog/1151692
补充:
上面的结果都是在一台电脑上的运行结果,尝试在不同电脑的缓存是否一致:
在自己电脑上输入 http://localhost:8080/test/test.jsp运行显示了 时间1;立即在另一台电脑上输入http://localhost:8080/test,(web.xml配置了主页为test.jsp)结果显示的却是 时间2,大惊!! 难道不同电脑的对同一页面请求后,会有不同的缓存? 也就是说服务器对每台电脑进行缓存页面,而不是指缓存一个,那这对我没任何帮助啊! 关键是演示的时候,老师在看,之前口口声声说解决了,现在出问题了,那我就囧大了! 幸好老师好像没看出来,老师走后,理解找问题点。
通过查网上资料:“CachingFilter功能可以对HTTP响应的内容进行缓存。这种方式缓存数据的粒度比较粗,例如缓存整张页面。它的优点是使用简单、效率高,缺点是不够灵活,可重用程度不高。EHCache使用SimplePageCachingFilter类实现Filter缓存。该类继承自CachingFilter,有默认产生cache key的calculateKey()方法,该方法使用HTTP请求的URI和查询条件来组成key。也可以自己实现一个Filter,同样继承CachingFilter类,然后覆写calculateKey()方法,生成自定义的key。” (摘自 http://www.cnblogs.com/hoojo/archive/2012/07/12/2587556.html) 。
疑问: 难道SimplePageCachingFilter利用calculateKey()计算key时的请求URI 包括请求主机的地址? 要是这样的话,那我岂不是要重写一个过滤器类,该类继承SimplePageCachingFilter,但覆盖其calculateKey()方法?
偶然发现刚才的两个URL不完全相同的,虽然最后请求的都是test.jsp。继续尝试:在不同电脑上分别打开两个窗口,并分别输入http://<ip>8080/test/test.jsp和http://<ip>8080/test,发现对于/test/test.jsp的页面的缓存是同一个,而/test的缓存是另外一个,用不同浏览器观察到的结果也符合。也就是说/test/test.jsp和/test的缓存是不一样的(Element),因为他们的URI不一样,所以计算出的key也不一样,因此element缓存条也不同!!!
还好,虚惊一场! 但以后要是真的要缓存主页,并且web.xml配置了主页,那如何解决这个问题呢? 还得是自己写个继承SimplePageCachingFilter的过滤类,然后覆盖calculateKey()方法;或者干脆写个虚的主页,这个主页做一个跳转,跳转到真正的主页(test.jsp).
在虚拟机里(jdk7+tomcat7)里加上了读取数据库,好使之后,尝试将该web放到添加到自己项目中(项目是用方正FIX BPMES平台开发,该平台用的是JDK5+tomcat5),结果提示“UnsupportedClassVersionError: Bad version number in .class file”,网上说是class类不兼容,我用eclipse改变编译jdk5,把连接数据库的class替换,但仍然不好使; 然后我直接在jsp里连接数据库,运行仍然提示刚才的问题,各种尝试,纠结了一晚上。网上搜tomcat5下连接数据库,没有用价值。终于搜jsp连接mssql2008时,看到有文章说“jdk6以后的jdbc包要用sqljdbc4.jar 包, 之前版本的JDK的用 sqljdbc.jar 包”,原来如此! 网上下载sqljdbc.jar,替换sqljdbc4.jar,通过!