在springcache之前
在没有使springcache之前我们使用缓存的方式是这样的:
Map<StoreKey, List<SpecialHall>> keyListHashMap = Maps.newHashMap();
DateTime dt = new DateTime().withHourOfDay(2).plusDays(1);
DateTime now = DateTime.now();
int toTwo = (int) (dt.getMillis() - now.getMillis()) / 1000;
List<SpecialHall> resList = Lists.newArrayList();
for (Integer cinemaId : cinemaIds) {
StoreKey storeKey = new StoreKey(CacheConstants.GDATA_STRING, String.format(CacheConstants.GATEWAY_SPECIALS_BY_CINEMAID, cinemaId));
keyListHashMap.put(storeKey, resList);
returnTocMap.put(cinemaId, transToTSpecialHallToApp(resList));
}
redisStoreClient.multiSet(keyListHashMap, toTwo);
这段代码我刚开始看的时候也觉得没问题,还觉得写的挺好的(因为是我写的偷笑),等我看到了springcache之后我觉得这段代码就不是那么的优雅了,总体来说就是代码的处理逻辑和缓存耦合在一起,降低了代码的可读性,不利于后期人员的维护;还有就是缓存切换的话成本很大,需要改动的地方比较多,风险成本比较高。
在springcache之后
springcache是什么?
首先,要明白springcache是一种解决缓存的方案,而不是一种具体的缓存方式(类似的Redis,memcache,ehcache等等)。
springcache的相关配置
pom配置:
这里需要注意spring应该是3.1+
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.8.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
springcache相关xml配置
<!-- ehcache -->
<cache:annotation-driven cache-manager="ehcacheManager"/>
<!-- 声明cacheManager -->
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="ehcacheManagerFactory" />
</bean>
<!-- cacheManager工厂类,指定ehcache.xml的位置 -->
<bean id="ehcacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
还需要配置具体的缓存:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">
<diskStore path="/Users/yuxi/work/myoschina/tmpdir"/>
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。
仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。
仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts
of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。
默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="60"
timeToLiveSeconds="60"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="dbCache" maxElementsInMemory="10000" eternal="false"
timeToLiveSeconds="1800" overflowToDisk="false" diskPersistent="true"/>
</ehcache>
springcache的相关代码实现
package com.yuxi.cache;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* Created by yuxi on 2017/9/28.
*/
@Service("cacheService")
public class CacheService {
@Cacheable(value = "dbCache", key = "'info_' + #id")
public Info getInfo(Integer id) {
System.out.println("from cache");
return getDb(id);
}
private Info getDb(Integer id) {
System.out.println("from db" + id);
return new Info(id);
}
@CachePut(value = "dbCache", key = "'info_' + #id")
public Info getInfo2(Integer id) {
System.out.println("from cache put");
return getDb(id);
}
@CacheEvict(value = "dbCache", key = "'info_' + #id")
public boolean delete(Integer id) {
System.out.println("delete");
return true;
}
}
相关测试类
package com.yuxi.main;
import com.yuxi.cache.CacheService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by yuxi on 2017/8/5.
*/
public class KnightMain {
public static void main(String[] args) {
// spring 应用上下文
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("knight.xml");
CacheService cacheService = (CacheService) applicationContext.getBean("cacheService");
cacheService.getInfo(1);
cacheService.getInfo(1);
cacheService.getInfo(1);
cacheService.getInfo(1);
cacheService.getInfo(1);
cacheService.getInfo2(1);
cacheService.getInfo2(1);
cacheService.getInfo2(1);
cacheService.delete(1);
}
}
相关的测试结果为:
from cache
from db1
from cache put
from db1
from cache put
from db1
from cache put
from db1
delete
springcache的相关注解说明:
三图胜过万言,图片来自郭老师的wiki,不要问我郭老师是谁?他是一个传说。
相关代码可以参考:springcache