下面格式整理有些混乱,spring3.1如何使用cache 缓存请参照:spring cache http://blog.csdn.net/partner4java/article/details/8600666
引自:<SPRING IN ACTION 2>
Spring程序有一种更优雅的缓存解决方案。Spring Modules项目(http://springmodules.dev.java.net)通过切面提供了缓存,它把通知应用于Bean方法来透明地对其结果进行缓存,而不是明确地指定要被缓存的方法。
Spring Modules对于缓存的支持涉及到一个代理,它拦截对Spring管理的Bean一个或多个的调用。当一个被代理的方法被调用时,Spring Modules Cache首先查阅一个缓存来判断这个方法是否已经被使用同样参数调用过,如果是,它会返回缓存里的值,实际的方法并不会被调用;否则,实际方法会被调用,其返回值会被保存到缓存里,以备方法下一次被调用时使用。
虽然Spring Modules会提供一个代理来拦截方法并把结果保存到缓存,它并没有提供一个实际的缓存解决方案,而是要依赖于第三方的缓存方案。可以使用的方案有多个,包括:
EHCache
GigaSpaces
JBoss Cache
JCS
OpenSymphony 的 OSCache
Tangosol 的 Coherence
我们为RoadRantz程序选择EHCache,主要是因为我以前使用它的经验及能够从www.ibibio.org的Maven仓库轻易获得。无论使用哪个缓存方案,对于Spring Modules Cache的配置基本上都是一样的。
首先要做的是新建一个Spring配置文件来声明缓存。虽然可以把Spring Modules Cache配置放到RoadRantz程序加载的任意一个Spring上下文配置文件里,但最好还是把他们分开,所以我们要创建roadrantz-cache.xml来保存缓存的配置。
与Spring上下文配置文件一样,randrantz-cache.xml也以<beans>元素为根。但为了利用Spring Modules 对EHCache的支持,我们要让<beans>元素能够识别ehcache命名空间:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:ehcache="http://www.springframework.org/schema/ehcache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/jeehttp://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/ehcache http://www.springframework.org/schema/cache/springmodules-ehcache.xsd">
我们为RoadRantz程序选择的是EhCache,如果想使用其他缓存方案,需要把Spring Modules命名究竟和规划声明修改为相应的内容。
URI和规划URI
无论选择哪种缓存,都可以使用一些Spring配置元素在Sping里对缓存进行配置。
Spring Modules的配置元素
配置元素 | 用途 |
<namespace:annotations> | 以Java5注解来声明被缓存的方式 |
<namespace:commons-attributes> | 以Jakarta通用属性元素数据来声明被缓存的方式 |
<namespace:config> | 在Spring XML里配置缓存方案 |
<namespace:proxy> | 在Spring XML里声明一个代理来声明被缓存的方式 |
在使用EHCache作为缓存方案时,需要告诉Spring到哪里寻找EHCache配置文件,这正是<ehcache:config>元素的用途所在:
<ehcache:config configLocation="classpath:ehcache.xml">
在此对configLocation属性的设置告诉Spring从程序类路径的根位置加载EHCache的配置。
配置EHCache
<ehcache>
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<diskStore path="java.io.tmpdir"/>
<!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager.
The following attributes are required for defaultCache:
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires.
i.e. The maximum amount of time between accesses before an element expires
Is only used if the element is not eternal.
Optional attribute. A value of 0 means that an Element can idle for infinity
timeToLiveSeconds - Sets the time to live for an element before it expires.
i.e. The maximum time between creation time and when an element expires.
Is only used if the element is not eternal.
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="rantzCache"
maxElementsInMemory="300"
eternal="false"
timeToIdleSeconds="500"
timeToLiveSeconds="500"
overflowToDisk="true"
/>
</ehcache>
<defulatCache>元素是必须的,描述了在没有找到其他缓存情况下所使用的缓存。<cache>缓存定义了另一个缓存,可以在ehcache.xml里出现0次或多次(每次针对定义的一个缓存)
EHCache的缓存配置属性
属性 | 用于指定 |
diskExpiryThreadIntervalSeconds | 磁盘过期线程运行的频率(以秒为单位),也就是磁盘持久的缓存清理过期项目的频率(默认是120秒) |
diskPersistent | 磁盘缓存在VM重新启动时是否保持(默认为false) |
eternal | 元素是否永恒。如果是永恒的,就永远不会过期(必须设置) |
maxElementsInMemory | 内存能够被缓存的最大元素数量(必须设置) |
memoryStoreEvictionPolicy | 当达到maxElementsInMemory时,如何强制进行驱逐。默认使用“最近使用(LRU)”策略,还可以使用“先入先出(FIFO)”和“较少使用(LFU)”策略。(默认是LRU) |
name | 缓存的名称(对于<cache>必须设置) |
overflowToDisk | 当内存缓存达到maxElementsInMemory时,是否可以溢出到磁盘(必须设置) |
timeToIdleSeconds | 导致元素过期的访问间接(以秒为单位)。设置为0标识元素可以永远空闲(默认值为0) |
timeToLiveSeconds | 元素在缓存里可以存在的时间(以秒为单位)。设置为0标识元素可以在缓存里永远存在而不过期(默认值是0) |
对于RoadRantz程序,我们配置了一个默认缓存(这是EHCache要求的),还配置了一个名为rantzCache的缓存作为主缓存。两个缓存都设置为最多可以容纳500个元素(不过期),访问频率最低的元素会被踢出,不允许磁盘溢出。
在Spring程序上下文里配置的EHCache之后,就可以声明哪个Bean和方法应该对结果进行缓存。首先,我们来声明一个代理来缓存RoadRantz DAO层里方法的返回值。
缓存的代理Bean
我们已经知道HibernateRantDao里的getRantsForDay()方法很适合进行缓存。再回到Spring上下文定义,我们要使用<ehcache:proxy>元素把一个代理包裹到HibernateRantDao,从而缓存从getRantsForDay()返回的全部内容:
<ehcache:proxy id="rantDao" refId="rantDaoTarget">
<ehcache:caching methodName="getRantsForDay" cacheName="rantzCache"/>
</ehcache:proxy>
<ehcache:caching>元素声明哪个方法要被拦截、其返回值要保存到哪个缓存。本例中,methodName被设置为getRantsForDay(),要使用的缓存是rantzCache。
我们可以根据需要在<ehcache:proxy>里声明多个<ehcache:caching>来描述Bean方法的缓存。我们可以让一个<ehcache:caching>用于所有被缓存的方法,也可以使用通配符为一个<ehcache:caching>元素指定多个方法。比如下面的<ehcache:caching>元素会代理缓存全部名称由get开头的方法:
<ehcache:caching method="get*" cacheName="rantzCache"/>
把数据放到缓存里只完成了一半的工作。在经过一段时间之后,缓存里一定会包含大量数据,其中很多没有意义的数据。最后,这些数据应该被清理,数据缓存周期重新开始。
刷新缓存
<ehcache:caching>元素声明的是要向缓存中添加数据的方法,而<ehcache:fluching>元素声明了会清空缓存的方法。举例来说,假设我们想在saveRant()方法被调用时清空rantzCache缓存,那么就应该使用如下的<ehcache:flushing>元素:
<ehcache:flushing methodName="saveRant" cacheName="rantzCache"/>
在默认情况下,cacheName属性里指定的缓存会在methodName被调用之后清空,但利用when属性可以指定清空的时机:
<ehcache:flushing methodName="saveRant" cacheName="rantzCache" when="before"/>
把when属性设置为before可以让缓存在saveRant()被调用之前清空。
声明一个被代替的内部Bean
注意<ehcache:proxy>的id和refld属性。由<ehcache:proxy>生成的代理的id是rantDao,然后这是HibernateRantDao Bean的id,因此,我们需要把这个真正的Bean重命名为rantDaoTarget。
如果觉得id/refId组合有些奇怪,我们还可以把目标Bean声明为<ehcache:proxy>的内部Bean:
<ehcache:proxy id="rantDao">
<bean class="....">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<ehcahe:caching methodName="getRantsForDay" cacheName="rantzCache"/>
</ehcache:proxy>
即使使用了内部Bean,我们仍然需要为每个要代理的Bean声明一个<ehcache:proxy>元素,为方法声明一个或多个<ehcache:caching>元素。
这个东东对我最大的吸引是,不再像以前,紧紧是hibernate对ehcache的支持了。也就是说,现在不论我用任何形式,我只是针对service或者Dao进行缓存就OK了。更易用
Demo1:
Demo2:
创建配置文件:
ehcache2.xml
bean-jdbc.xml
beans-jdbc.xml
一个用户我后面单元测试的基础类:
我的实体bean:
接口:
实现类:
我一般写完service,都会先测试一下,我的Junit:
我简单写了个jsp测试一下:
但是怎么测试呢?呵呵,我就是些了一个列表,然后打开,查看,比如现在十条数据,我打开了一个mysql管理工具,删了几条数据,刷新这个界面还是十条数据,没少。就验证了缓存这点。
还有另外一种不利用spring支持的xml配置标签和注解的形式,利用切面编程,改天再整理出来,不过,我还是很喜欢这种,所以第一时间就先搞的这个,但是有一点注意的是,包,这个利用的是springmodules项目,所以要单独引入springmodules相关的ehcahe,的却难找。还有,ehcache的核心包,和核心包需要的相关包。
spring-modules-cache-0.8.jar
ehcache-core-2.4.0.jar。。。
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/aspectjrt.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/aspectjweaver.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/c3p0-0.9.1.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-dbcp-1.2.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-logging.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-pool-1.3.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/mysql-connector-java-5.1.7-bin.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/antlr-2.7.6.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/cglib-2.2.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/commons-collections-3.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/dom4j-1.6.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/hibernate3.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/javassist-3.9.0.GA.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/jta-1.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/log4j-1.2.15.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/spring.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-api-1.6.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/slf4j-jdk14-1.6.1.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/ehcache-core-2.4.0.jar"/>
<classpathentry kind="lib" path="WebRoot/WEB-INF/lib/spring-modules-cache-0.8.jar"/>