文档章节

java redis 通用组建

小灰灰Blog
 小灰灰Blog
发布于 2016/04/02 21:56
字数 1692
阅读 178
收藏 11

前言

redis 是个干嘛的 ? 看官网:http://redis.io/

一句话,这里redis当做缓存(或者本来就是), 利用java写一个jedis的读写的组建

1. 组建代码

no bb, review code

package com.mushroom.hui.common.cache;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by july on 16/4/1.
 */
public class CacheWrapper implements InitializingBean {
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CacheWrapper.class);

    private JedisPool masterJedis;
    private List<JedisPool> slaveJedisList;

    private String masterConf;
    private String slaveConf;
    private int maxIdle;
    private int minIdle;
    private int maxTotal;
    private int timeout;
    private int database;

    public String getMasterConf() {
        return masterConf;
    }

    public void setMasterConf(String masterConf) {
        this.masterConf = masterConf;
    }

    public String getSlaveConf() {
        return slaveConf;
    }

    public void setSlaveConf(String slaveConf) {
        this.slaveConf = slaveConf;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }

    public void setMinIdle(int minIdle) {
        this.minIdle = minIdle;
    }

    public int getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getDatabase() {
        return database;
    }

    public void setDatabase(int database) {
        this.database = database;
    }

    private class ConfAddress {
        private String ip;
        private int port;

        public String getIp() {
            return ip;
        }

        public void setIp(String ip) {
            this.ip = ip;
        }

        public int getPort() {
            return port;
        }

        public void setPort(int port) {
            this.port = port;
        }

        public ConfAddress(String conf) {
            init(conf);
        }

        private void init(String conf) {
            if (!StringUtils.contains(conf, ":")) {
                return;
            }

            String[] pair = StringUtils.split(conf, ":");
            if (pair == null || pair.length != 2) {
                return;
            }

            this.ip = pair[0];
            this.port = Integer.parseInt(pair[1]);
        }

        public boolean isIllegal() {
            return StringUtils.isBlank(ip) || port <= 0;
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 池基本配置
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal <= 0 ? 300 : maxTotal);
        config.setMaxIdle(maxIdle <= 0 ? 10 : maxIdle);
        config.setMinIdle(minIdle <= 0 ? 3 : minIdle);
        config.setMaxWaitMillis(timeout <= 0 ? 1000 : timeout);
        config.setTestOnBorrow(false);


        // init master jedis
        ConfAddress masterAddr = new ConfAddress(masterConf);
        if (masterAddr.isIllegal()) {
            throw new JedisException("master jedis conf is error!");
        }
        masterJedis = new JedisPool(config, masterAddr.getIp(), masterAddr.getPort(), this.timeout, null, this.database);


        // init slave jedis
        String[] slaveConfs = StringUtils.split(slaveConf, ",");
        if (slaveConfs == null || slaveConfs.length == 0) {
            slaveJedisList = Collections.emptyList();
        }
        slaveJedisList = new ArrayList<>(slaveConfs.length);
        ConfAddress slaveTmpAddr;
        for (String conf: slaveConfs) {
            slaveTmpAddr = new ConfAddress(conf);
            if(slaveTmpAddr.isIllegal()) {
                continue;
            }
            JedisPool slaveJedis = new JedisPool(config, slaveTmpAddr.getIp(), slaveTmpAddr.getPort(),
                    this.timeout, null, this.database);
            slaveJedisList.add(slaveJedis);
        }
    }




    final int MASTER_JEDIS = 0;
    final int SLAVE_JEIDS = 1;
    // 保证线程安全的自动技术器
    private AtomicInteger chooseCounter = new AtomicInteger();

    /**
     * 获取使用的jedis,这里采用标准的一主多备模式
     * @param type
     * @return
     */
    public JedisPool getJedisPool(int type) {
        if (type == MASTER_JEDIS) {
            return masterJedis;
        }

        if (CollectionUtils.isEmpty(slaveJedisList)) {
            return masterJedis;
        }


        final int chooseIndex = this.chooseCounter.incrementAndGet();
        final int index = chooseIndex % slaveJedisList.size();
        return slaveJedisList.get(index);
    }


    public String get(String key) {
        if(StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("key is null!");
        }

        Jedis jedis = null;
        JedisPool pool = getJedisPool(SLAVE_JEIDS);
        try {
            jedis = pool.getResource();
            String ans = jedis.get(key);
            return ans;
        } catch (Exception e) {
            logger.error("get string from cache error!");
            logger.error("Exception: {}", e);
            return null;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 采用fastJson作为序列化工具
     * @param key cache key
     * @param clz object class
     * @param <T> type
     * @return object in cache!
     */
    public <T> T getObject(String key, Class<T> clz) {
        if(StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("key is null");
        }

        Jedis jedis = null;
        JedisPool pool = getJedisPool(SLAVE_JEIDS);
        try {
            jedis = pool.getResource();
            String ans = jedis.get(key);
            if (StringUtils.isBlank(ans) || "nil".equals(ans)) {
                return null;
            }

            T obj = JSON.parseObject(ans, clz);
            return obj;
        } catch (Exception e) {
            logger.error("get object from cache error!");
            logger.error("Exception: {}", e);
            return null;
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }


    public boolean set(String key, String value, int expire) {
        if(StringUtils.isBlank(key) || StringUtils.isBlank(value) || expire <= 0) {
            throw new IllegalArgumentException("key || value || expire are illegal");
        }

        Jedis jedis = null;
        JedisPool pool = getJedisPool(MASTER_JEDIS);
        try {
            jedis = pool.getResource();
            String ans = jedis.setex(key, expire, value);
        } catch (Exception e) {
            logger.error("set string into cache error!");
            logger.error("Exception: {}", e);
            return false;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return true;
    }


    public boolean setObject(String key, Object value, int expire) {
        if (StringUtils.isBlank(key) || value == null || expire <= 0) {
            throw new IllegalArgumentException("key value expire are illegal!");
        }

        Jedis jedis = null;
        JedisPool pool = getJedisPool(MASTER_JEDIS);
        try {
            jedis = pool.getResource();
            String data = JSON.toJSONString(value);
            jedis.setex(key, expire, data);
        } catch (Exception e) {
            logger.error("set object into cache error!");;
            logger.error("Exception: {}", e);
            return false;
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
        return true;
    }

}

配置文件 cache.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:beans="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">

    <!-- 下面的这个扫描很重要,用于建立uri与controller指尖的映射 -->
    <context:component-scan base-package="com.mushroom.hui"/>
    <context:annotation-config/>
    <beans:annotation-driven/>

    <bean id="cachePropertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="2" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath*:conf/cache.properties</value>
            </list>
        </property>
    </bean>

    <bean id="cacheWrapper" class="com.mushroom.hui.common.cache.CacheWrapper">
        <property name="masterConf" value="${cache.masterConfig}" />
        <property name="slaveConf" value="${cache.slaveConfigs}" />
        <property name="timeout" value="${cache.timeout}" />
        <property name="database" value="${cache.database}" />
        <property name="maxTotal" value="${cache.maxTotal}" />
        <property name="maxIdle" value="${cache.maxIdle}" />
        <property name="minIdle" value="${cache.minIdle}" />
    </bean>
</beans>

cache.properties

cache.masterConfig=127.0.0.1:6379
cache.slaveConfigs=127.0.0.1:6379
cache.passwd=123
cache.timeout=60
cache.database=5
cache.maxTotal=10
cache.maxIdle=4
cache.minIdle=2

test测试文件

package com.mushroom.hui.test;

import com.mushroom.hui.common.cache.CacheWrapper;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by yihui on 16/4/2.
 */
public class CacheWrapperTest {

    private final static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CacheWrapperTest.class);

    private CacheWrapper cacheWrapper;

    @Before
    public void init() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:spring/*.xml");
        cacheWrapper = applicationContext.getBean("cacheWrapper", CacheWrapper.class);
    }

    private class Point {
        String name;
        Float x;
        float y;

        public Point(String name, Float x, float y) {
            this.name = name;
            this.x = x;
            this.y = y;
        }

        public float getY() {
            return y;
        }

        public void setY(float y) {
            this.y = y;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Float getX() {
            return x;
        }

        public void setX(Float x) {
            this.x = x;
        }
    }

    @Test
    public void cacheTest() {
        String key = "hello_001";
        String value = "woca";

        boolean ans = cacheWrapper.set(key, value, 600);
        logger.info("The result is: {}", ans);

        Object obj = cacheWrapper.get(key);
        logger.info("The obj is {}", obj);


        Map<String, List<Point>> map = new HashMap<>(2);
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point("a1", 123f, 123));
        pointList.add(new Point("a2", 10f, 20f));
        map.put("a", pointList);

        List<Point> pointList2 = new ArrayList<>();
        pointList2.add(new Point("b1", 10f, 110f));
        pointList2.add(new Point("b2", -10f, -20f));
        pointList2.add(new Point("b3", -100f, -200f));
        map.put("b2", pointList2);

        String key2 = "world_001";
        boolean ans2 = cacheWrapper.setObject(key2, map, 600);
        logger.info("The ans2 is  {}", ans2);
        Object result = cacheWrapper.getObject(key2, map.getClass());
        logger.info("Thre result2 is {}", result);
    }
}

2. 代码解析

由于项目工程是机遇spring框架的,所以上面的代码中可以很清晰的看到soring bean的相关内容

如果不了解spring,也不想使用spring相关的东西,可以无视上面的xml, properties 文件,直接用上面的java类即可(附件给出相关代码)

- 一主多备模式

上面的组建支持一主多备的使用方式,写maser,读slave

- 代码解析

  1. 初始话redis相关的配置参数
  1. 初始化 JedisPool 实例

  2. get/set设计与实现

  3. 参数初始化 redis相关的常用参数:JedisPoolConfig, (masterAddr, port), (slaveAddr, port), timeout

  maxTotal 最多的jedis实例
  maxIdel, minIdel 最大最小的空闲jedis实例
  masterConfig: master redis的ip(or域名)和端口号
  slaveConfig: slave redis的ip(or域名)和端口号
  timeout: 链接超时时间(大于这个时间则抛连接超时异常)

这些参数的初始化是由spring框架完成的,在bean的声明处,即将properties中的相关参数注入到CacheWrapper中的成员变量中

why redisPool not jedis? - 并发量大时(qps高),耽搁jedis处理不过来!!! - 使用pool减少了jedis实例的频繁销毁和新建的开销

  1. JedisPool 初始化 聚焦 afterPropertiesSet方法,jedisPool的初始化主要调用的是public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port, int timeout, final String password, final int database);

这段代码逻辑也很简单,稍稍注意一下slaveJedisPool 是一个列表(一主多备嘛)

  1. get/set 方法 在聚焦get/set方法之前需要先关注一下 getJedisPool()方法, why? 代码中有一个masterPool和多个slavePool,那么选择哪一个来使用,也是一个问题
  • getJedisPool 逻辑 :

    • 写redis,选用 masterPool
    • 读redis,轮询(利用了线程安全的AutomicInteger)使用slavePool,没有salvePool时,读masterPool
  • get(key) / getObject(key, clz) 从redis读

    • 获取jedisPool
    • get jedis实例
    • 从redis中获取存储对象
    • 处理对象(如getObject中使用fastJson反序列化),返回
    • 关闭jedis实例(其实是扔到了pool)
  • set(key, value, expire) / setObject(key, object, expire) 写入redis

    • 获取jedisPool
    • get jedis实例
    • 处理object(fastJson序列化)
    • 塞入redis
    • 关闭redis实例

基本流程完结

© 著作权归作者所有

小灰灰Blog
粉丝 203
博文 222
码字总数 395172
作品 0
武汉
程序员
私信 提问
J2EE 框架 - Spring

Spring Framework 是一个开源的 Java/Java EE 全功能栈(full-stack)的应用程序框架,以 Apache 许可证形式发布,也有 .NET 平台上的移植版本。该框架基于 Expert One-on-One Java EE Desi...

匿名
2008/09/07
636.3K
91
0.0.6-Linux安装软件

1、jdk 检查是否已安装jdk : rpm -qa | grep jdk ,若无文件即未安装 创建用于存放jdk的文件夹:mkdir java (位置在/root/java) 用FileZilla 将下载好的linux的jdk上传至java文件中 解压:t...

静以修身2025
06/03
5
0
Redisson项目介绍

Redisson项目介绍 Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid)。充分的利用了Redis键值数据库提供的一系列优势,基于Java实用工具包中常用接口,为使用者提...

jackygurui
2016/12/02
2
0
Spring的网友评论

Spring Framework 是一个开源的Java/Java EE全功能栈(full-stack)的应用程序框架,以Apache许可证形式发布,也有.NET平台上的移植版本。该框架基于 Expert One-on-One Java EE Design and...

红薯
2009/12/11
560
13
Go commons pool 1.0 发布,通用 Go 语言对象池

Go commons pool是一个通用的go语言对象池,基于Java版本的Apache Commons Pool改写。Go commons pool实现了Java版本的主要功能,改写了大多数Java版本的测试用例,测试覆盖率达到90%,性能测...

jolestar
2016/01/18
2.4K
11

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
6
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部