重点:
- 配置ehcache配置文件,并配置好缓存策略:主要有在内存中的最大数量,在硬盘中的最大数目,是否在关闭服务器之前将缓存写入本地磁盘.最大空闲缓存数,缓存最大存活时间,缓存数据是否永久有效,数据过期策略(三选一)等待
- 在spring配置文件中引入ehcache的工厂Bean和管理bean,并注册缓存注解驱动:
- 注意注解的使用,和value,key的设置策略
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!-- 指定一个文件目录,当EhCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
<diskStore path="D:/ehcache"/>
<!-- 设定缓存的默认数据过期策略 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="10"
timeToLiveSeconds="20"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<!--
cache元素的属性:
name:缓存名称
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大
eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false
overflowToDisk:true表示当内存缓存的对象数目达到了
maxElementsInMemory界限后,会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。
diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。
//配置为true,才会在系统停止运行的时候把缓存到磁盘,并且再次执行的时候,会直接从磁盘读取缓存的数据;
//配置为false,在系统重启期间,不会把缓存数据写入磁盘
diskPersistent:是否缓存虚拟机重启期数据,是否持久化磁盘缓存,
当这个属性的值为true时,系统在初始化时会在磁盘中查找文件名 为cache名称,
后缀名为index的文件,这个文件中存放了已经持久化在磁盘中的cache的index,
找到后会把cache加载到内存,要想把 cache真正持久化到磁盘,写程序时注意执行net.sf.ehcache.Cache.put(Element element)后要调用flush()方法。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒
timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,如果处于空闲状态的时间超过了timeToIdleSeconds属性 值,这个对象就会过期,EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,则表示对象可以无限 期地处于空闲状态
timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有 效。如果该属性值为0,则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有 意义
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
-->
<cache name="cacheTest"
maxElementsInMemory="10"
maxElementsOnDisk="0"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="100"
timeToLiveSeconds="200"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU" />
<cache
name="cache2"
maxElementsInMemory="10"
maxElementsOnDisk="0"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="160"
diskPersistent="true"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hgh</groupId>
<artifactId>ehcache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<!-- spring版本号 -->
<spring.version>4.3.3.RELEASE</spring.version>
<!-- junit版本号 -->
<junit.version>4.12</junit.version>
</properties>
<dependencies>
<!-- 添加Spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!--单元测试依赖 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--spring单元测试依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!-- ehcache 相关依赖 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.2</version>
</dependency>
</dependencies>
</project>
package com.hgh.service;
public interface EhCacheTestService {
public String getTimestamp(String param);
public String getTimestamp2(String param,String param2);
}
package com.hgh.service;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class EhCacheTestServiceImpl implements EhCacheTestService{
@Cacheable(value="cacheTest",key="#param")
public String getTimestamp(String param) {
Long timestamp = System.currentTimeMillis();
return timestamp.toString();
}
//@Cacheable(value="cacheTest")
@Cacheable(value="cache2")
public String getTimestamp2(String param, String param2) {
// TODO Auto-generated method stub
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
String strdate = "";
strdate = simpleDateFormat.format(new Date());
System.out.println("执行了getTimestamp2,时间"+strdate+"参数1:"+param+"参数2"+param2);
return "执行了getTimestamp2,时间"+strdate+"参数1:"+param+"参数2"+param2;
}
}
<?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:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache-4.3.xsd">
<!-- 自动扫描注解的bean -->
<context:component-scan base-package="com.hgh.service" />
<!--
使用Spring的缓存注解
开启注解
Spring为缓存功能提供了注解功能,但是你必须启动注解。
你有两个选择:
(1) 在xml中声明
像上一节spring-ehcache.xml中的做法一样,使用<cache:annotation-driven/>
-->
<!-- 启用缓存注解开关 -->
<cache:annotation-driven cache-manager="cacheManager" />
<!--
Spring3.1开始添加了对缓存的支持。和事务功能的支持方式类似,缓存抽象允许底层使用不同的缓存解决方案来进行整合。
Spring4.1开始支持JSR-107注解。
注:我本人使用的Spring版本为4.1.4.RELEASE,目前Spring版本仅支持Ehcache2.5以上版本,但不支持Ehcache3。
绑定Ehcache
org.springframework.cache.ehcache.EhCacheManagerFactoryBean这个类的作用是加载Ehcache配置文件。
org.springframework.cache.ehcache.EhCacheCacheManager这个类的作用是支持net.sf.ehcache.CacheManager。
-->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcache"></property>
</bean>
<!-- 加载ehcache配置文件 -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache-setting.xml"></property>
</bean>
<!--
http://www.cnblogs.com/jingmoxukong/p/5975994.html
(2) 使用标记注解
你也可以通过对一个类进行注解修饰的方式在这个类中使用缓存注解。
范例如下:
@Configuration
@EnableCaching
public class AppConfig {
}
注解基本使用方法
Spring对缓存的支持类似于对事务的支持。
首先使用注解标记方法,相当于定义了切点,然后使用Aop技术在这个方法的调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。
下面三个注解都是方法级别:
@Cacheable
表明所修饰的方法是可以缓存的:当第一次调用这个方法时,它的结果会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。
这个注解可以用condition属性来设置条件,如果不满足条件,就不使用缓存能力,直接执行方法。
可以使用key属性来指定key的生成规则。
@CachePut
与@Cacheable不同,@CachePut不仅会缓存方法的结果,还会执行方法的代码段。
它支持的属性和用法都与@Cacheable一致。
@CacheEvict
与@Cacheable功能相反,@CacheEvict表明所修饰的方法是用来删除失效或无用的缓存数据。
下面是@Cacheable、@CacheEvict和@CachePut基本使用方法的一个集中展示:
@Caching
如果需要使用同一个缓存注解(@Cacheable、@CacheEvict或@CachePut)多次修饰一个方法,就需要用到@Caching。
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)
@CacheConfig
与前面的缓存注解不同,这是一个类级别的注解。
如果类的所有操作都是缓存操作,你可以使用@CacheConfig来指定类,省去一些配置。
@CacheConfig("books")
public class BookRepositoryImpl implements BookRepository {
@Cacheable
public Book findBook(ISBN isbn) {...}
}
-->
</beans>
package com.hgh.ehcache.test;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import com.hgh.service.EhCacheTestService;
import com.hgh.service.EhCacheTestServiceImpl;
public class EhCacheTestServiceTest extends SpringTestCase{
@Autowired
private EhCacheTestService ehCacheTestService;
@Test
public void getTimestampTest() throws InterruptedException{
System.out.println("第一次调用:" + ehCacheTestService.getTimestamp("param"));
Thread.sleep(2000);
System.out.println("2秒之后调用:" + ehCacheTestService.getTimestamp("param"));
Thread.sleep(11000);
System.out.println("再过11秒之后调用:" + ehCacheTestService.getTimestamp("param"));
}
@Test
public void getTimestampTest2() throws InterruptedException{
System.out.println("第一次调用:" + ehCacheTestService.getTimestamp2("a","b"));
Thread.sleep(2000);
System.out.println("2秒之后调用:" + ehCacheTestService.getTimestamp2("a","b"));
Thread.sleep(11000);
System.out.println("再过3秒之后调用:" + ehCacheTestService.getTimestamp2("a","b"));
}
@Test
public void getTimestampTest3() throws InterruptedException{
Integer i = 0;
for (i = 1; i < 100; i++) {
System.out.println("第"+i+"次调用:" + ehCacheTestService.getTimestamp2(i.toString(),"b"));
}
i = 0;
for (i = 1; i < 100; i++) {
System.out.println("222第"+i+"次调用:" + ehCacheTestService.getTimestamp2(i.toString(),"b"));
}
System.out.println("第一次调用:" + ehCacheTestService.getTimestamp2("a","b"));
Thread.sleep(2000);
System.out.println("2秒之后调用:" + ehCacheTestService.getTimestamp2("a","b"));
Thread.sleep(11000);
System.out.println("再过3秒之后调用:" + ehCacheTestService.getTimestamp2("a","b"));
}
}
package com.hgh.ehcache.test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//指定bean注入的配置文件
@ContextConfiguration(locations = { "classpath:application.xml" })
//使用标准的JUnit @RunWith注释来告诉JUnit使用Spring TestRunner
@RunWith(SpringJUnit4ClassRunner.class)
public class SpringTestCase extends AbstractJUnit4SpringContextTests{
}