JFinal使用技巧-EhCache与Redis自由切换

有个项目使用的缓存是EhCache,  这个客户的访问量单机抗不住, 就用了多部署, 发现有些梗, 是缓存导致的, 没有同步... 于是用上了Redis  . 业务代码尽量不能动... 就写了个插件, EhCache与Redis自由切换 , 下面分享一下

这个分享适合老项目微改造,不想太多改动的。集群项目推荐直接使用j2cache这个开源中国红薯大佬的工具。

Redis 安装 配置
菜鸟教程网:
http://www.runoob.com/redis/redis-install.html

http://blog.csdn.net/libaineu2004/article/details/49004195


JFinal 中配置

看手册: 第八 章 RedisPlugin

数据库ActiveRecordPlugin 默认使用的是
EhCache
com.jfinal.plugin.activerecord.cache;

在这里得自己模仿写一个 可切换的Cache工具了.

MyCache.java
public class MyCache implements ICache {

    private static String getCacheType() {
        return PropKit.get("cache_type", "ehcache");
    }

    public static boolean isEhCache() {
        return "ehcache".equals(getCacheType());
    }

    public static boolean isRedis() {
        return "redis".equals(getCacheType());
    }

    @Override
    public <T> T get(String cacheName, Object key) {
        if (isEhCache()) {
            return CacheKit.get(cacheName, key);

        } else if (isRedis()) {
            return Redis.use(cacheName).get(key);
        }
        return null;
    }

    @Override
    public void put(String cacheName, Object key, Object value) {
        if (isEhCache()) {
            CacheKit.put(cacheName, key, value);

        } else if (isRedis()) {
            Redis.use(cacheName).set(key, value);
        }
    }

    @Override
    public void remove(String cacheName, Object key) {
        if (isEhCache()) {
            CacheKit.remove(cacheName, key);

        } else if (isRedis()) {
            Redis.use(cacheName).del(key);
        }

    }

    @Override
    public void removeAll(String cacheName) {
        if (isEhCache()) {
            CacheKit.removeAll(cacheName);

        } else if (isRedis()) {
            Cache cache = Redis.use(cacheName);
            cache.del(cache.keys("*").toArray());
        }

    }

}

放进数据库连接插件  ActiveRecordPlugin
JFinalConfig中

/**
     * 配置插件
     */
    public void configPlugin(Plugins me) {
        // 配置DruidPlugin数据库连接池插件
        DruidPlugin druidPlugin = createDruidPlugin();
        me.add(druidPlugin);
        
        // 配置ActiveRecord插件
        ActiveRecordPlugin arp = new ActiveRecordPlugin(DbKit.MAIN_CONFIG_NAME, druidPlugin);
        me.add(arp);
        arp.setContainerFactory(new CaseInsensitiveContainerFactory(true));// 大小写不敏感
        
        // 缓存可切换使用
        arp.setCache(new MyCache());
        
        // 所有主数据元 配置在 MappingKit 中
        _MappingKit.mapping(arp);
        
        // 缓存设置
        if(MyCache.isRedis()){
            //根据ehcache.xml 中来 栗子~ 
            String[] cacheName = {"cacheName_1","cacheName_2",
            "cacheName_3","cacheName_4","cacheName_5","cacheName_6",
            "cacheName_7","cacheName_8","cacheName_9"};
            for (int i = 0; i <= 9; i++) {
                RedisPlugin newsRedis = 
                  new RedisPlugin( cacheName[i],  "192.168.1.240",  6379,  0,  "JFinal2011",  i);
                me.add(newsRedis);
            }
        }else if (MyCache.isEhCache()) {
            me.add(new EhCachePlugin());
        }
        
    }


好了, 最后导包
图片.png
写个测试类:

public class RedisTest {

    public static void main(String[] args) {


        for (int i = 0; i <= 9; i++) {
         testRedis("cacheName_" + i, "192.168.1.240", 6379, 0 , "JFinal2011", i);
         System.out.println("------------------------");
        }
    }

     public static void testRedis(final String cacheName, String host, int port) {
        System.out.println("cacheName="+ cacheName + "  host="+ host + " port="+ port);
        
        RedisPlugin rpMy = new RedisPlugin( cacheName,  host,  port,  timeout,  password,  database);
        rpMy.start();

        new Thread(){
            public void run() {
                
                for (int i = 0; i < 10000; i++) {
                    new Thread(){
                        public void run() {
                            String name = getName();
                            Cache use = Redis.use(cacheName);
                            use.set("k" + name, "value_key_" + cacheName + "_"+name);
                            
                            Object v = use.get("k" + name);
                            System.out.println(v);
                            use.del("k" + name);
                        }
                    }.start();
                }
            }
        }.start();
        
    }

}


@JFinal   非常感谢老大的指导!!! 已经做修改了~  爽!



评论区

JFinal

2017-05-28 17:34

总体上是这么玩的,但为啥要启动那么多的 redis server 实例呢? 一个不行么?

杜福忠

2017-05-28 18:21

@JFinal
以前项目中用的是EhCache , CacheKit 里面管理了多个 Cache ,
我要改用 Redis , Redis 类里面要对上以前的多个 Cache ,

那一个Redis Cache 不就是 一个redis server 实例 了么 ?

杜福忠

2017-05-28 18:29

@JFinal
如果用一个Redis Cache 存取删的时候 ,
用:
Cache.set( cacheName+key , value)
Cache.get(cacheName+key)
Cache.del(cacheName+key)
这样吗 ? 就是这块感觉怪怪的...

JFinal

2017-05-28 18:42

@杜福忠 多个 Cache 也不用这么玩啊, redis 是有库的概念的,为不同的 cacheName 分配到不同的 redis db 就可以了,为每个 cacheName 创建一个 RedisPlugin 对象就可以了

JFinal

2017-05-28 18:42

@杜福忠 记得搞定后再回来分享一下,你这么来玩肯定是搞复杂了

JFinal

2017-05-28 18:44

@JFinal 就算你只用一个 RedisPlugin 实例,你也可以将 Ehcache 的 cacheName key 的形式转换成 redis 的 cacheName + key,将这个值的整体当成是 redis 的 key 来用

JFinal

2017-05-28 18:45

@杜福忠 此外,即便是用 ehcache ,也可以通过配置集群来实现数据同步,也可以学一下 oschina 红薯的开源项目 j2cache 让 ehcache 与 redis 配合实现集群

杜福忠

2017-05-28 20:18

@JFinal 感谢老大指点~ 已经修改了~ 再去看看红薯教主的j2cache

爪爪

2017-07-28 09:20

请教一下,刚才波总提及的修改多个redis实例 能提供参考一下吗

杜福忠

2017-07-28 09:27

@爪爪 RedisPlugin 挂参不一样就可以了 , 可以挂不同的IP,端口等, 来切换到不同的或多个 redis 服务 , 通过 cacheName 即可取到他们了 ,

爪爪

2017-07-28 14:11

@杜福忠 哦哦,在请教一个问题,isEhCache(),isRedis()你是怎么判断是哪个缓存的,系统从哪里就开始确定你到底使用的是哪个缓存?getCacheType()这个方法我测试的都是ehcache,那这样的话你config里面配置生成RedisPlugin 实例就没有执行,这个地方请教一下,谢谢了

杜福忠

2017-07-28 17:09

@爪爪
上面例子中是在 PropKit.get("cache_type", "ehcache"); 中配置的,
配置文件中有个叫 cache_type=xxx 的

private static String getCacheType() {
return PropKit.get("cache_type", "ehcache");
}

-------------------------------------------------
还是看你的需求, 可以说说业务场景, 分析一下怎么搭配比较方便
如果是动态的随时去更改,
可以把 PropKit.get("cache_type", "ehcache");
改成 :
private static final ThreadLocal cache_type = new ThreadLocal();
private static String getCacheType() {
String cache_type = cache_type.get("cache_type")
return cache_type != null ? cache_type : "ehcache";
}

publicstatic String setCacheType(String cache_type) {
cache_type.set(cache_type);
}
//快捷
publicstatic String setCacheTypeEhcache() {
setCacheType("ehcache");
}
publicstatic String setCacheTypeXxxcache() {
setCacheType("xxxx");
}

杜福忠

2017-07-28 17:19

@爪爪

如果是 为某个数据源配置不同的cache 那么
// 配置ActiveRecord插件 的时候 就可以切换了,
ActiveRecordPlugin arp1 = new ActiveRecordPlugin("xxx1", druidPlugin1);
// 缓存使用
arp1.setCache(new RedisCache());

ActiveRecordPlugin arp2 = new ActiveRecordPlugin("xxx2", druidPlugin2);
// 缓存使用
arp2.setCache(new XxxxCache());

爪爪

2017-07-28 17:25

万分感谢

canca

2017-10-11 09:27

谢谢了,已成功换成j2cache

你是谁我是谁

2017-11-08 10:24

@杜福忠 大佬,很厉害的呦。分享不错。

你是谁我是谁

2017-11-09 14:35

大佬,想问你下,你的数据连接配置写在那里了。

这句话里 DruidPlugin druidPlugin = {createDruidPlugin();这个地方也是自己添加的吗,我的jfinal里没有这个,也是需要自己填写的。}请求指教

杜福忠

2017-11-09 16:04

@你是谁我是谁 自己写的 一个静态 方法 里面只是 : new DruidPlugin (xxx...) 其他的功能 就可以 直接共用 这个方法了

杜福忠

2017-11-09 16:05

@你是谁我是谁 参考官网的 jfinal-3.2_demo.zip 里面有

你是谁我是谁

2017-11-09 16:11

@杜福忠 嗯嗯,最近在学这个redis缓存。然后不是很明白。谢谢 !!!

hotsmile

2018-11-13 14:31

我分页查询想用echache,目前表数据300W+,如果不用缓存,页面要好几秒,但是现在 用了缓存,新增又不刷新了,纠结? @JFinal,请给支招!!

杜福忠

2018-11-13 15:15

@hotsmile 新增后, 清除一下缓存, 不就可以了么? 还是你这有其他业务?

JFinal

2018-11-14 00:30

@hotsmile 用好 EvictInterceptor 拦截器做缓存清除即可

hotsmile

2018-11-14 08:50

@杜福忠 有些页面不能粗暴的直接全部清除,我觉得海哥的文章写得不错,https://my.oschina.net/yangfuhai/blog/745715

maxwade

2019-03-29 10:53

基本看懂了,相应的EvictInterceptor也需要修改了。

热门分享

扫码入社