文档章节

动态构建J2Cache以及注意事项

傲娇字符
 傲娇字符
发布于 05/25 09:01
字数 824
阅读 254
收藏 0

一直以来,我们都是将数据字典等信息放在Redis缓存中,避免使用的时候,穿透到数据库层面,同时提升性能。最近突然发现线上频繁出现Redis连接超时等异常,经过跟踪,发现新增了一个字典表,有三万多行记录,始料未及的事情终究还是发生了。于是需要增加应用内存级别的缓存,同时还要保持与redis一致。

最近红薯的J2Cache发版有点频繁(快成娱乐新闻了),成功的引起了我的注意,基本满足此需求,由于J2Cache底层基于Ehcache,每次启动,都要往内存加载缓存数据,导致本地调试每次重启变得很慢,所以后续会基于J2Cache进行扩展(ehcache的磁盘缓存策略,必须确保应用正常退出才行)。

注意事项1:配置参数名不能直接使用j2cache.properties中示例

由于项目本身使用了配置中心,只能基于动态构建J2Cache的方式进行集成。此时发现了J2Cache的两个BUG,第一个直接导致红薯连夜发版(说好无BUG,反手就是一巴掌,再次给红薯道歉);第二个问题,每次启动的时候,没有读取到配置信息,而代码转换出现空指针异常(我认为这种强转是会出事的,建议官方在后续版本改一下写法)经过红薯的指点,在使用Properties方式进行动态添加配置的时候,需要将redis.的前缀去掉,所以只能在J2CacheBuilder.init(config);之前通过代码去掉前缀,此坑必须绕开。

代码参见下面的removePrefix方法。

注意事项2:不想使用集群广播通知应该如何设置

另外如果不想使用Redis集群或者集群广播功能,需要config.setBroadcast("none");里面的参数,其实建议官方能改成枚举。

示例代码如下:

package com.chz.apps.common.j2cache;

import com.chz.apps.common.cache.LocalCache;
import com.chz.apps.common.redisson.RedissionTools;
import net.oschina.j2cache.CacheChannel;
import net.oschina.j2cache.J2CacheBuilder;
import net.oschina.j2cache.J2CacheConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

/**
 * J2Cache工具类
 * @Author gongstring(gongstring@foxmail.com)
 */
public class J2CacheUtil {

    private static Logger logger = LoggerFactory.getLogger(J2CacheUtil.class);

    private static CacheChannel channel = null;

    /**
     * 初始化启动
     */
    public static void start(){
        Object server = LocalCache.getInstance().get(RedissionTools.REDIS_SERVER_IP);
        Object port = LocalCache.getInstance().get(RedissionTools.REDIS_SERVER_PORT);
        Object timeout = LocalCache.getInstance().get(RedissionTools.REDIS_TIMEOUT);
        Object auth = LocalCache.getInstance().get(RedissionTools.REDIS_AUTH);
        Object database = LocalCache.getInstance().get(RedissionTools.REDIS_DATABASE);
        if(server != null && StringUtils.isNotBlank(server.toString()) && port != null && Integer.parseInt(port.toString()) > 0){
            try {

                Properties l1cacheProperties = new Properties();
                l1cacheProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("j2cache/caffeine.properties"));

                Properties l2cacheProperties = new Properties();
                l2cacheProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("j2cache/j2cache.properties"));
                //自定义redis配置连接
                l2cacheProperties.put("redis.hosts",server+":"+port);
                l2cacheProperties.put("redis.timeout",timeout);
                if(auth != null){
                    l2cacheProperties.put("redis.password",auth);
                }

                if(database != null){
                    l2cacheProperties.put("redis.database",database);
                }

                J2CacheConfig config = new J2CacheConfig();
                //不使用集群通知
                config.setBroadcast("none");
                config.setL1CacheName("caffeine");
                config.setL1CacheProperties(l1cacheProperties);

                config.setL2CacheName("redis");
                config.setL2CacheProperties(removePrefix(l2cacheProperties,"redis."));
                J2CacheBuilder builder = J2CacheBuilder.init(config);
                channel = builder.getChannel();

                logger.info("J2Cache启动成功");
            }catch (Exception e){
                e.printStackTrace();
                logger.error("J2Cache启动失败:{}",e);
            }
        }else{

            logger.info("J2Cache启动失败,没有配置二级缓存Redis的参数信息");
        }


    }

    public static void close(){
        if(channel != null){
            channel.close();
        }
    }

    public static CacheChannel getChannel(){
        return channel;
    }

    private static Properties removePrefix(Properties properties,String prefix){
        if(properties == null)
            return null;

        Properties result = new Properties();
        Iterator<Map.Entry<Object, Object>> it = properties.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = it.next();
            if(entry.getKey().toString().startsWith(prefix)){
                result.put(entry.getKey().toString().substring(prefix.length()),entry.getValue());
            }else{
                result.put(entry.getKey(),entry.getValue());
            }
        }
        return result;
    }

    public static void main(String[] args) throws Exception{
        start();

        // 通用没有具体业务意义的代码,只是为了保证主线程不退出
        synchronized (J2CacheUtil.class) {
            J2CacheUtil.class.wait();
        }
    }

}


© 著作权归作者所有

共有 人打赏支持
傲娇字符
粉丝 5
博文 39
码字总数 15196
作品 0
武汉
架构师
私信 提问
J2Cache 2.2.1 正式版发布,开源中国两级缓存框架

J2Cache 2.2.1 正式版发布了。J2Cache 是 OSChina 目前正在使用的两级缓存框架。第一级缓存使用 Ehcache,第二级缓存使用 Redis 。由于大量的缓存读取会导致 L2 的网络成为整个系统的瓶颈,因...

周其
01/10
973
5
沉寂多时,J2Cache 2.0 首个 Beta 测试版发布

J2Cache 已经有很长时间没有更新了,一年?一年多?还是更长?反正已经很久了。因为实在是太忙了,在这里先感谢一下参与 J2Cache 贡献的开发者,他们是:https://gitee.com/ld/J2Cache/cont...

红薯
2017/12/22
2.8K
18
J2Cache 新增 Hibernate 5 支持,感谢 @tandy 贡献

想了解 J2Cache 是一个什么开源项目,请阅读 这篇博客。 J2Cache 刚新增对 Hibernate 5 的支持,提供了 j2cache-hibernate5 模块,可以方便在 Hibernate 5 中启用 J2Cache 缓存。 该模块由 ...

红薯
09/28
1K
10
J2Cache 新增 Mybatis 支持模块,代码少到没 Bug

花了点时间撸了个 MyBatis 的 J2Cache 支持模块,含注释共八十多行代码 (J2CacheAdapter.java),再有 Bug 我就真的要退役了。 使用方法很简单,请看 https://gitee.com/ld/J2Cache/tree/mast...

红薯
05/15
2.8K
49
J2Cache 2.2.0-beta 发布,开源中国两级缓存框架

J2Cache 2.2.0-beta 发布,J2Cache 是 OSChina 目前正在使用的两级缓存框架。第一级缓存使用 Ehcache,第二级缓存使用 Redis 。由于大量的缓存读取会导致 L2 的网络成为整个系统的瓶颈,因此...

周其
01/08
3K
21

没有更多内容

加载失败,请刷新页面

加载更多

初探Spring Cloud(一)

1. 什么是Spring Cloud? Spring提供了一系列工具,可以帮助开发人员迅速搭建分布式系统中的公共组件(比如:配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,...

__HuWei
13分钟前
0
0
Mac配置ssh免密钥登录

Mac终端每次使用ssh -p 22 user@ip登录很是麻烦,下面介绍配置ssh免密钥登录: cd ~/.ssh下创建conf文件,写入以下配置: Host test HostName ip Port 22 IdentityFile /Users/t/key/test.p...

littlemesieV
28分钟前
1
0
Spark2.0操作ES

ES提供了支持包来方便的操作ES。首先添加ES的依赖maven: <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch-spark-20_2.11</artifactId> <version>6.2.0</ver......

守望者之父
30分钟前
1
0
专业术语

1、防御性编程 DruidDataSource类有一个init方法,我们在spring中配置druid时,都会指定 init-method='init'. 而且DruidDataSource也在其他地方,诸如getConnection()方法里作了防御性编程, 也就...

still5656
32分钟前
1
0
微信开发--测试账号相关

1、微信公众平台选择代码开发后,其平台上的部分功能会不可用 可在开发者工具中选择开通测试账号,进行相关的功能调试(测试账号出微信支付不可调试外,其他功能基本上都可以调试) 2、测试账号...

Code辉
38分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部