Jfinal中使用EhCache缓存

1、前言

Ehcache是一个快速的、轻量级的、易于使用的、进程内的缓存。它支持read-only和read/write 缓存,内存和磁盘缓存。是一个非常轻量级的缓存实现,而且从1.2之后就支持了集群。

简单地说来,ehcache有以下特点:

  • 快速、简单.
  • 多种缓存策略
  • 缓存数据有两级:内存和磁盘,因此无需担心容量问题
  • 缓存数据会在虚拟机重启的过程中写入磁盘
  • 可以通过RMI、可插入API 等方式进行分布式缓存
  • 具有缓存和缓存管理器的侦听接口
  • 支持多缓存管理器实例,以及一个实例的多个缓存区域
  • 提供Hibernate的缓存实现

具体ehcache配置和使用可参考我另一篇博客:ehcache的使用
这里重点说明,ehcache在JJfinal中的使用


2、Jfinal中使用ehcache

2.1、引入jar包

项目中想使用ehcache缓存,首先需要引入对应jar,Jfinal项目也不例外,但无需在ehcache官网下载,Jfinal文件中就有相应jar包,以“Jfinal-3.0”为了,在Jfinal官网上下载“jfinal-3.0-all.zip”压缩包,并解压:
Jfinal中使用EhCache缓存_第1张图片

解压完成后,依次进入目录“jfinal-3.0-all”->“jfinal-3.0-lib”->“ehcache”,其中“jfinal-3.0-lib”文件夹存放着Jfinal需要的全部jar包,也包含ehcache的jar包
Jfinal中使用EhCache缓存_第2张图片
“ehcache”文件夹中有以上三个jar包和一个标准的ehcache配置文件;将以上三个jar包都引入项目,并将配置文件“ehcache.xml”放在“src”或“res”目录下
Jfinal中使用EhCache缓存_第3张图片


2.2、在项目中配置EhCache

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));
    }
}   

2.3、EhCachePlugin

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();
    }

2.4、CacheKit

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

2.5、CacheInterceptor

除了工具类外,还可以通过配置拦截器的方式使用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,意味着没有查询数据库,直接从缓存中取值:
Jfinal中使用EhCache缓存_第4张图片

上例中的用法将使用 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如:


2.6、EvictInterceptor

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/

你可能感兴趣的:(Jfianl技术总结)