博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
动态构建J2Cache以及注意事项
阅读量:6090 次
发布时间:2019-06-20

本文共 4591 字,大约阅读时间需要 15 分钟。

  hot3.png

一直以来,我们都是将数据字典等信息放在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
> it = properties.entrySet().iterator(); while (it.hasNext()) { Map.Entry
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(); } }}

转载于:https://my.oschina.net/yyqz/blog/1818427

你可能感兴趣的文章
阿里云公共镜像、自定义镜像、共享镜像和镜像市场的区别 ...
查看>>
shadowtunnel v1.7 发布:新增上级负载均衡支持独立密码
查看>>
Java线程:什么是线程
查看>>
mysql5.7 创建一个超级管理员
查看>>
【框架整合】Maven-SpringMVC3.X+Spring3.X+MyBatis3-日志、JSON解析、表关联查询等均已配置好...
查看>>
要想成为高级Java程序员需要具备哪些知识呢?
查看>>
带着问题去学习--Nginx配置解析(一)
查看>>
onix-文件系统
查看>>
java.io.Serializable浅析
查看>>
我的友情链接
查看>>
多线程之线程池任务管理通用模板
查看>>
CSS3让长单词与URL地址自动换行——word-wrap属性
查看>>
CodeForces 580B Kefa and Company
查看>>
开发规范浅谈
查看>>
Spark Streaming揭秘 Day29 深入理解Spark2.x中的Structured Streaming
查看>>
鼠标增强软件StrokeIt使用方法
查看>>
本地连接linux虚拟机的方法
查看>>
某公司面试java试题之【二】,看看吧,说不定就是你将要做的题
查看>>
BABOK - 企业分析(Enterprise Analysis)概要
查看>>
Linux 配置vnc,开启linux远程桌面
查看>>