本文对Ehcache和Memcached进行了简单的封装,这样对于客户端程序无需了解ehcache和memcached的差异,仅需要配置缓存的Provider类就可以在二者之间进行切换,Provider实现类通过Spring IoC注入。
cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING/DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="cacheProvider" class="org.frank1234.spring.memcached.EhcacheCacheProvider">
</bean>
<bean id="cacheManager" class="org.frank1234.spring.memcached.CacheManager">
<property name = "cache">
<ref bean="cacheProvider"></ref>
</property>
</bean>
</beans>
public interface ICache {
public void put(String key, Object obj) throws Exception;
public Object get(String key) throws Exception;
public void remove(String key) throws Exception;
}
public class EhcacheCacheProvider implements ICache{
private static CacheManager manager ;
private static Cache ehcache;
public EhcacheCacheProvider(){
manager = CacheManager.getInstance();
ehcache = manager.getCache("helloworldCache");
}
@Override
public void put(String key, Object obj) throws Exception {
Element elemnt = new Element(key,obj);
ehcache.put(elemnt);
}
@Override
public Object get(String key) throws Exception {
Element element = ehcache.get(key);
return element.getObjectValue();
}
@Override
public void remove(String key) throws Exception {
ehcache.remove(key);
}
}
public class MemcachedCacheProvider implements ICache {
static {
try {
initPool();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static MemCachedClient client;
private static void initPool() throws Exception{
Properties props = getProperties();
String[] servers = ((String)props.get("servers")).split(",");
SockIOPool pool = SockIOPool.getInstance();
pool.setServers(servers);
pool.setFailover(Boolean.valueOf((String)props.get("failover")));
pool.setInitConn(Integer.parseInt((String)props.get("initConn")));
pool.setMinConn(Integer.parseInt((String)props.get("minConn")));
pool.setMaxConn(Integer.parseInt((String)props.get("maxConn")));
pool.setMaintSleep(Integer.parseInt((String)props.get("maintSleep")));
pool.setNagle(Boolean.valueOf((String)props.get("magle")));
pool.setSocketTO(Integer.parseInt((String)props.get("socketTO")));
pool.setAliveCheck(Boolean.valueOf((String)props.get("aliveCheck")));
pool.initialize();
}
private static Properties getProperties() throws Exception{
Properties props = new Properties();
InputStream in = MemcachedCacheProvider.class.getResourceAsStream("/memcached.properties");
props.load(in);
return props;
}
public MemcachedCacheProvider(){
client = new MemCachedClient();
}
@Override
public void put(String key, Object obj) throws Exception {
client.set(key.toString(),obj);
}
@Override
public Object get(String key) throws Exception {
return client.get(key);
}
@Override
public void remove(String key) throws Exception {
client.delete(key);
}
}
public class CacheManager {
private ICache cache;
public void setCache(ICache cache) {
this.cache = cache;
}
public ICache getCache() throws Exception{
return cache;
}
}
public class CacheMain {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
}
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void testCache() throws Exception{
ApplicationContext factory = new ClassPathXmlApplicationContext("cache.xml");
CacheManager cacheManager = (CacheManager)factory.getBean("cacheManager");
ICache cache = cacheManager.getCache();
cache.put("key","value");
System.out.println(cache.get("key"));
}
}
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="false"
monitoring="autodetect" dynamicConfig="true">
<!-- 将缓存数据写到硬盘上的目录,文件名为"缓存名1.data"的隐藏文件,程序运行结束后会自动删除,如果要查看可以通过Thread.sleep(60*1000)暂停住程序-->
<diskStore path="d:/ehcache"/>
<!--默认的缓存策略
maxElementsInMemory :内存中存放的最大对象数,这是是对象的数量,maxBytesLocalHeap是对象的大小,jdk不提供直接计算对象大小的api,ehcache实现了计算对象大小的功能。具体可参见源码cache.calculateInMemorySize(),计算方法比较复杂。
eternal:true表示永不过期,默认是false,如果设置成true,则timeToIdleSeconds和timeToLiveSeconds就失效了。
overflowToDisk:true表示如果缓存的数量超过了maxElementsInMemory则将缓存数据放入硬盘中,
timeToIdleSeconds:允许对象处于空闲状态的时间,超过此时间则过期,清掉缓存数据。
timeToLiveSeconds:允许对象最大存活时间,超过此时间则过期,清掉缓存数据。这个时间大于timeToIdleSeconds才有意义。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
-->
<defaultCache maxElementsInMemory="1000" eternal="false"
overflowToDisk="true" timeToIdleSeconds="30" timeToLiveSeconds="60">
</defaultCache>
<cache name="helloworldCache" maxElementsInMemory="1000"
maxEntriesLocalDisk="10000" eternal="false" overflowToDisk="true"
diskSpoolBufferSizeMB="20" timeToIdleSeconds="10" timeToLiveSeconds="20"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
memcached.properties
servers=localhost:11211
failover=true
initConn=10
minConn=5
maxConn=250
maintSleep=30
nagle=false
socketTO=3000
aliveCheck=true