Ehcache在程序启动的时候并不会立即去加载位于磁盘上的数据到内存,而是在数据被用到的时候去加载(lazy load)。因此在cache启动的时候,其内部没有数据。如果我们想在用到这些数据之前,它们全部被装载进内存,应该怎么做?
Ehcache提供了BootstrapCacheLoader机制来解决这个问题,在Cache被激活之前,它会得到运行。并且有两种模式:同步和异步。如果是同步模式,在CacheMana启动之前,加载便会完成;如果是异步模式,在CacheManager启动的时候,加载会在后台继续,而不是等到所需数据被需要的时候。
我们只需要实现接口BootstrapCacheLoader定义自己的加载器MyBootstrapCacheLoader,继承BootstrapCacheLoaderFactory实现一个具体的加载工厂MyBootstrapCacheLoaderFactory即可实现数据的预热。
MyBootstrapCacheLoader负责实现怎么将数据加载进Cache,我们可以进行个性化的实现。MyBootstrapCacheLoaderFactory是一个具体的加载工厂,负责创建加载器实例,我们需要实现一些抽象方法。
下面看具体的代码实现(Java)。
MyBootstrapCacheLoader.java:
/**
*
* Copyright (c) 2004-2014 All Rights Reserved.
*/
package com..test.encache;
import java.util.List;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author
* @version $Id: CustomBootstrapCacheLoader.java, v 0.1 2014年10月18日 上午10:57:26 Exp $
*/
public class MyBootstrapCacheLoader implements BootstrapCacheLoader {
private static final Logger logger = LoggerFactory
.getLogger(MyBootstrapCacheLoaderFactory.class);
StatesDAO statesDAO;
boolean asynchronous;
/**
* @see net.sf.ehcache.bootstrap.BootstrapCacheLoader#load(net.sf.ehcache.Ehcache)
*/
public void load(Ehcache cache) throws CacheException {
logger.info("load your cache with whatever you want....");
List keys = cache.getKeys();
for (int i = 0; i < keys.size(); i++) {
logger.info("keys->" + keys.get(i));
}
try {
List dataList = getStatesDAO().findAllStates();
cache.put(new Element(CacheConstants.KEY_ARRAY[0], dataList.get(0)));
cache.put(new Element(CacheConstants.KEY_ARRAY[1], dataList.get(1)));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
logger.info("load end....");
}
/**
* @see net.sf.ehcache.bootstrap.BootstrapCacheLoader#isAsynchronous()
*/
public boolean isAsynchronous() {
return asynchronous;
}
/**
* @see java.lang.Object#clone()
*/
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public StatesDAO getStatesDAO() {
return statesDAO;
}
public void setStatesDAO(StatesDAO statesDAO) {
this.statesDAO = statesDAO;
}
/**
* Setter method for property asynchronous.
*
* @param asynchronous value to be assigned to property asynchronous
*/
public void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
}
MyBootstrapCacheLoaderFactory.java
/**
*
* Copyright (c) 2004-2014 All Rights Reserved.
*/
package com.test.encache;
import java.util.Properties;
import net.sf.ehcache.bootstrap.BootstrapCacheLoader;
import net.sf.ehcache.bootstrap.BootstrapCacheLoaderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* bootstrap cache loader
*
* @author
* @version $Id: MyBootstrapCacheLoaderFactory.java, v 0.1 2014年10月17日 下午8:02:55 Exp $
*/
public class MyBootstrapCacheLoaderFactory extends BootstrapCacheLoaderFactory {
private final String ASYNCHRONOUS_PROPERTY_KEY = "ASYNCHRONOUS";
@Autowired
private StatesDAO statesDAO;
public MyBootstrapCacheLoaderFactory() {
super();
// TODO Auto-generated constructor stub
}
private static final Logger logger = LoggerFactory
.getLogger(MyBootstrapCacheLoaderFactory.class);
@Override
public BootstrapCacheLoader createBootstrapCacheLoader(Properties properties) {
logger.info("MyBootstrapCacheLoaderFactory : create a BootstrapCacheLoader");
MyBootstrapCacheLoader loader = new MyBootstrapCacheLoader();
statesDAO = new StatesDAO();
loader.setStatesDAO(statesDAO);
loader.setAsynchronous(getAsyncFromProperty(properties));
return loader;
}
private boolean getAsyncFromProperty(Properties properties) {
String asynchronous = properties.getProperty(ASYNCHRONOUS_PROPERTY_KEY);
return Boolean.valueOf(asynchronous);
}
}
使用了Cache的读取磁盘数据的方法在StatesDAO类中,对此我们只是进行了模拟,从数据库中读取数据。
StatesDAO.java
/**
*
* Copyright (c) 2004-2014 All Rights Reserved.
*/
package com.test.encache;
import java.util.ArrayList;
import java.util.List;
import com.googlecode.ehcache.annotations.Cacheable;
/**
*
* @author
* @version $Id: StatesDAO.java, v 0.1 2014年10月17日 下午8:07:05 Exp $
*/
public class StatesDAO {
//annotation based caching and the name of cache should be defined in ehcache.xml.
@Cacheable(cacheName = "stateCache")
public List findAllStates() {
List dataList = new ArrayList();
//your call to database that returns a list of objects
dataList.add("value1");
dataList.add("value2");
return dataList;
}
}
Cache配置myehcache.xml:
src/config/myehcache.xml
/**
*
* Copyright (c) 2004-2014 All Rights Reserved.
*/
package com.test.encache;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
*
* @author
* @version $Id: BootstrapCacheLoader.java, v 0.1 2014年10月18日 上午11:31:06 Exp $
*/
public class BootstrapCacheLoaderTest {
private static String log4jFileName = "src/config/log4j.properties";
private static String xmlFileName = "src/config/ApplicationContext.xml";
private static String ehcacheXmlFileName = "src/config/myehcache.xml";
private static final Logger logger = LoggerFactory
.getLogger(BootstrapCacheLoaderTest.class);
private static CacheManager ehCacheManager;
public static void main(String[] args) {
configProperty();
xmlLoad(ehcacheXmlFileName);
String[] cacheNamesStrings = ehCacheManager.getCacheNames();
logger.info("the number of caches in ehCacheManager : " + cacheNamesStrings.length);
Cache cache = ehCacheManager.getCache(CacheConstants.CACHE_NAME1);
Element element = cache.get(CacheConstants.KEY_ARRAY[0]);
logger.info("the element of key " + CacheConstants.KEY_ARRAY[0] + " is " + element);
}
/**
* config properties
*
*/
private static void configProperty() {
Properties properties = new Properties();
FileInputStream istream;
try {
istream = new FileInputStream(log4jFileName);
properties.load(istream);
istream.close();
} catch (FileNotFoundException e) {
logger.error("File not found", e);
} catch (IOException e) {
logger.error("load file erroe", e);
} finally {
}
//properties.setProperty("log4j.appender.file.File",logFile);
PropertyConfigurator.configure(properties);
logger.info("config properties success.");
}
private static void xmlLoad(String fileName) {
ApplicationContext ctx = new FileSystemXmlApplicationContext(xmlFileName);
ehCacheManager = (CacheManager) ctx.getBean("ehCacheManager");
}
}
Ehcache关于预热机制的官方文档
Load EhCache diskstore content into memory
How to load data to Ehcache when the application starts