java redis 通用组建
时间:2022-04-27
本文章向大家介绍java redis 通用组建,主要内容包括前言、1. 组建代码、2. 代码解析、- 代码解析、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
前言
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
- 代码解析
- 初始话redis相关的配置参数
- 初始化 JedisPool 实例
- get/set设计与实现
- 参数初始化 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实例的频繁销毁和新建的开销
- JedisPool 初始化 聚焦 afterPropertiesSet方法,jedisPool的初始化主要调用的是
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port, int timeout, final String password, final int database);
这段代码逻辑也很简单,稍稍注意一下slaveJedisPool 是一个列表(一主多备嘛)
- 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实例
基本流程完结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法