Ehcache是一个快速的、轻量级的、易于使用的、进程内的缓存。它支持read-only和read/write 缓存,内存和磁盘缓存。是一个非常轻量级的缓存实现,而且从1.2之后就支持了集群。
简单地说来,ehcache有以下特点:
具体ehcache配置和使用可参考我另一篇博客:ehcache的使用
这里重点说明,ehcache在JJfinal中的使用
项目中想使用ehcache缓存,首先需要引入对应jar,Jfinal项目也不例外,但无需在ehcache官网下载,Jfinal文件中就有相应jar包,以“Jfinal-3.0”为了,在Jfinal官网上下载“jfinal-3.0-all.zip”压缩包,并解压:
解压完成后,依次进入目录“jfinal-3.0-all”->“jfinal-3.0-lib”->“ehcache”,其中“jfinal-3.0-lib”文件夹存放着Jfinal需要的全部jar包,也包含ehcache的jar包
“ehcache”文件夹中有以上三个jar包和一个标准的ehcache配置文件;将以上三个jar包都引入项目,并将配置文件“ehcache.xml”放在“src”或“res”目录下
JFinal 已经集成了ehcache缓存,以plugin形式存在,叫“EhCachePlugin”。需要在项目的DemoConfig.java中配置后才能使用:
public class DemoConfig extends JFinalConfig {
/**
* 配置插件
*/
public void configPlugin(Plugins me) {
URL url = getClass().getResource("res/ehcache.xml");
me.add(new EhCachePlugin(url));
}
}
com.jfinal.plugin.ehcache.EhCachePlugin继承了 com.jfinal.plugin.IPlugin
接口;在EhCachePlugin中主要是生成cacheManager,并将cacheManager放在CacheKit 中:
1、在EhCachePlugin中有多个构造函数,都是传递不同类型的ehcache配置文件参数或直接传递CacheManager ,供后面使用(上例中使用了URL形式的参数)
public class EhCachePlugin implements IPlugin {
private static CacheManager cacheManager;
private String configurationFileName;
private URL configurationFileURL;
private InputStream inputStream;
private Configuration configuration;
public EhCachePlugin() {
}
public EhCachePlugin(CacheManager cacheManager) {
EhCachePlugin.cacheManager = cacheManager;
}
public EhCachePlugin(String configurationFileName) {
this.configurationFileName = configurationFileName;
}
public EhCachePlugin(URL configurationFileURL) {
this.configurationFileURL = configurationFileURL;
}
public EhCachePlugin(InputStream inputStream) {
this.inputStream = inputStream;
}
public EhCachePlugin(Configuration configuration) {
this.configuration = configuration;
}
}
2、每个Plugin都会有start方法,在项目启动时执行。 EhCachePlugin 在start方法中调用createCacheManager()方法,创建CacheManager;并将CacheManager放在CacheKit中【CacheKit.init(cacheManager)】,供项目使用
public boolean start() {
createCacheManager();
CacheKit.init(cacheManager);
return true;
}
private void createCacheManager() {
if (cacheManager != null)
return ;
if (configurationFileName != null) {
cacheManager = CacheManager.create(configurationFileName);
return ;
}
if (configurationFileURL != null) {
cacheManager = CacheManager.create(configurationFileURL);
return ;
}
if (inputStream != null) {
cacheManager = CacheManager.create(inputStream);
return ;
}
if (configuration != null) {
cacheManager = CacheManager.create(configuration);
return ;
}
cacheManager = CacheManager.create();
}
com.jfinal.plugin.ehcache.CacheKit是ehcache缓存的操作工具类,在EhCachePlugin中,已经将cacheManager放在CacheKit 中(给CacheKit的cacheManager参数赋值),所以可以在项目中通过CacheKit,来使用ehcache缓存技术
public void index() {
int pageNumber = getParaToInt(0, 1);
Page blogPage = CacheKit.get("blogTest", "blogList");
if(blogPage == null){
blogPage = Blog.me.paginate(pageNumber, 10);
CacheKit.put("blogTest", "blogList",blogPage);
}
setAttr("blogPage",blogPage);
render("blog.html");
}
CacheKit 中最重要的两个方法是get(String cacheName, Objectkey)与put(String cacheName,Object key, Object value)。get 方法是从cache中取数据,put方法是将数据放入cache。参数cacheName与ehcache.xml中的
name属性值对应; 参数key是指取值用到的key;参数 value 是被缓存的数据。对应上例的ehcache.xml配置如下:
<cache name="blogTest"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="30"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
cache>
ehcache.xml的配置在此不做展开说明,详见我的另一片文章
除了以上介绍的get(String cacheName, Objectkey)方法外,CacheKit还提供了CacheKit.get(String, String, IDataLoader)方法,使用方式如下:
public void index() {
Page blogPage = CacheKit.get("blogTest", "blogList", new IDataLoader(){
public Object load(){
return Blog.me.paginate(getParaToInt(0, 1), 10);
}
});
setAttr("blogPage",blogPage);
render("blog.html");
}
CacheKit.get方法提供了一个IDataLoader接口,该接口中的load()方法在缓存值不存在时才会被调用。该方法的具体操作流程是:首先以 cacheName=blogTest 以及 key=blogList 为参数去缓存取数据,如果缓存中数据存在就直接返回该数据,不存在则调用 IDataLoader.load()方法来获取数据,并将获取到的数据通过put(cacheName, key, data)放在cache中。
CacheKit中的其他方法:
List getKeys(String cacheName)
:获取名称为“cacheName”的cache中全部key。remove(String cacheName, Object key)
:删除某一缓存removeAll(String cacheName)
:删除cache中的全部缓存static Cache getOrAddCache(String cacheName)
:根据cacheName获取或创建cache。 getOrAddCache方法是put、get方法的基础。
如果ehcache.xml中未配置以cacheName命名的cache,getOrAddCache方法会调用 cacheManager.addCacheIfAbsent(cacheName)创建cache,缓存策略使用 default
除了工具类外,还可以通过配置拦截器的方式使用ehcache缓存。
CacheInterceptor可以将 action 所需数据全部缓存起来,下次请求到来时如果cache存在则直接使用数据并render,而不会去调用action。此用法可使 action 完全不受 cache 相关代码所污染,即插即用,以下是示例代码:
@Before(CacheInterceptor.class)
public void index() {
int pageNumber = getParaToInt(0, 1);
Page blogPage = Blog.me.paginate(pageNumber, 10);
setAttr("blogPage", blogPage);
render("blog.html");
}
运行结果如下,可以看出第二次执行,没有打印sql,意味着没有查询数据库,直接从缓存中取值:
上例中的用法将使用 actionKey作为cacheName(使用具体的url(actionKey+参数)作为cacheKey),在使用之前需要在 ehcache.xml中配置以actionKey命名的cache 如:
,注意 actionKey 作为cacheName配置时斜杠”/”不能省略(如果没有在ehcache.xml配置对应的cache,系统会使用default,详见CacheKit的getOrAddCache方法)
。此外CacheInterceptor 还可以与CacheName注解配合使用,以此来取代默认的 actionKey 作为 cacheName,以下是示例代码:
@Before(CacheInterceptor.class)
@CacheName("bloglist")
public void index() {
int pageNumber = getParaToInt(0, 1);
Page blogPage = Blog.me.paginate(pageNumber, 10);
setAttr("blogPage", blogPage);
render("blog.html");
}
以上用法需要在ehcache.xml中配置名为bloglist的cache如:
EvictInterceptor 可以根据 CacheName 注解自动清除缓存。以下是示例代码:
@Before(EvictInterceptor.class)
@CacheName("bloglist")
public void delete() {
Blog.me.deleteById(getParaToInt());
redirect("/blog");
}
上例中的用法将清除 cacheName 为 blogList 的缓存数据,与其配合的CacheInterceptor 会自动更新 cacheName 为 blogList 的缓存数据。
查看以下EvictInterceptor源代码可以看到,在执行完
inv.invoke()
后,调用CacheKit.removeAll(buildCacheName(inv))
方法,将名为cacheName的缓存全部清除。
public class EvictInterceptor implements Interceptor{
final public void intercept(Invocation inv) {
inv.invoke();
CacheKit.removeAll(buildCacheName(inv));
}
}
参考:《Jfinal用户手册》
Jfinal官网:http://www.jfinal.com/