17课:关于Springboot和JedisCluster结合使用,自定义缓存的序列化方式
简介
现在大部分项目多多少少都会碰到一下功能会使用到缓存的地方;本文通过redis集群进行演示
通过JedisCluster实现redis缓存操作的内容;同事自定义缓存的序列化方式,在通过客户端进行命令行操作方便查看对应的key-value 的值内容.
项目结构
代码简介
1. redis.properties文件
主要是关于redis的一些配置项内容包含集群的服务器地址,密码等配置项内容
cache.redis.servers=51000:redis;51001:redis;51002:redis
cache.redis.password=gm2018
cache.redis.maxWaitMillis=1000
cache.redis.maxTotal=1000
cache.redis.minIdle=8
cache.redis.maxIdle=100
cache.redis.testOnBorrow=true
cache.redis.testOnReturn=true
cache.redis.connectionTimeout=10000
cache.redis.soTimeout=800
cache.redis.maxRedirections=6
2.pom.xml文件
引入JedisCluster
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.3.0</version>
</dependency>
3.RedisConfig.java
里面关于JedisCluster配置项内容然后主要通过RedisUtil 工具类中的方法实现里面的不同数据格式缓存的调用
@Configuration
@ConfigurationProperties(prefix="cache.redis")
@PropertySource(value = "classpath:redis.properties", encoding = "UTF-8")
public class RedisConfig {
//redis服务
private String servers;
//密码
private String password;
//poolConfig配置
private boolean testOnBorrow;
private boolean testOnReturn;
private int maxTotal;
private int maxIdle;
private int minIdle;
private long maxWaitMillis;
private int connectionTimeout;
private int soTimeout;
private int maxRedirections;
/**
* 通过获取配置文件进行JedisCluster配置.
* @author khy
* @createTime 2020年11月20日下午3:51:45
* @return
*/
@Bean("jedisCluster")
public JedisCluster createJedisCluster(){
try {
Set<HostAndPort> jedisClusterNode = new HashSet();
//这个是切分redis集群的配置,因为是同一台机器所以端口不同所以端口放前面了
Splitter.on(";").withKeyValueSeparator(":").split(servers).forEach((k,v)->{
if(StringUtils.isNoneBlank(k,v)){
jedisClusterNode.add(new HostAndPort(v, Integer.valueOf(k)));
}
});
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxWaitMillis(maxWaitMillis);
poolConfig.setMaxTotal(maxTotal);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
poolConfig.setTestOnBorrow(testOnBorrow);
poolConfig.setTestOnReturn(testOnReturn);
JedisCluster cluster = new JedisCluster(jedisClusterNode, connectionTimeout, soTimeout,maxRedirections,password,poolConfig);
return cluster;
} catch (Exception e) {
throw new RuntimeException("redis服务地址配置无效不符合条件");
}
}
// get/set方法省略
}
4.SerializerUtil
默认的一般key 或者 字符串类型的value都可以通过 StringRedisSerializer 进行序列化操作
如果是实体类对象需要通过自定义FastjsonRedisSerializer 里面实际是通过 com.alibaba.fastjson.JSON
对实体对象进行序列化和反序列化;在通过命令获取redis中value值能看到具体的内容,默认的序列化方式则二进制码
public class SerializerUtil {
/**
* key
*/
private static RedisSerializer<String> keySerializer = new StringRedisSerializer();
/**
* Object value
*/
private static RedisSerializer<Object> valueSerializer = new FastjsonRedisSerializer();
/**
* 序列化redis的key值
* @author khy
* @createTime 2019年11月12日上午10:32:34
* @param key
* @return
*/
public static byte[] rawKey(String key) {
return keySerializer.serialize(key);
}
/**
* 根据value的类型序列化value
* @author khy
* @createTime 2019年11月11日下午9:21:07
* @param obj
* @return
*/
public static <V>byte[] rawValue(V obj){
return valueSerializer.serialize(obj);
}
/**
* 批量序列化Object类型
* @author khy
* @createTime 2019年11月12日上午10:48:22
* @param list
* @return
*/
public static <T> byte[][] rawValues(List<T>list) {
final byte[][] rawValues = new byte[list.size()][];
int i = 0;
for (Object value : list) {
rawValues[i++] = rawValue(value);
}
return rawValues;
}
public static byte[][] rawKeys(List<String>list) {
final byte[][] rawKeys = new byte[list.size()][];
int i = 0;
for (String value : list) {
rawKeys[i++] = rawKey(value);
}
return rawKeys;
}
public static<V>Map<byte[], byte[]> rawValues(Map<String,V> map) {
final Map<byte[], byte[]> hashes = new LinkedHashMap<byte[], byte[]>(map.size());
for (Entry<String, V> entry : map.entrySet()) {
hashes.put(rawKey(entry.getKey()),rawValue(entry.getValue()));
}
return hashes;
}
/**
通过fastJson完成序列化操作
*/
public class FastjsonRedisSerializer implements RedisSerializer<Object> {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private static SerializerFeature[] features = {SerializerFeature.WriteClassName};
public Object deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length == 0) {
return null;
}
try {
return JSON.parse(bytes);
} catch (Exception ex) {
throw new SerializationException("Could not read JSON: "
+ ex.getMessage(), ex);
}
}
public byte[] serialize(Object t) throws SerializationException {
if (t == null) {
return new byte[0];
}
try {
return JSON.toJSONBytes(t, features);
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: "
+ ex.getMessage(), ex);
}
}
}
/**字符串的操作*/
public class StringRedisSerializer implements RedisSerializer<String>{
private final Charset charset;
public StringRedisSerializer() {
this(Charset.forName("UTF8"));
}
public StringRedisSerializer(Charset charset) {
Assert.notNull(charset, "Charset must not be null!");
this.charset = charset;
}
public String deserialize(byte[] bytes) {
return (bytes == null ? null : new String(bytes, charset));
}
public byte[] serialize(String string) {
return (string == null ? null : string.getBytes(charset));
}
}
/反序列化//
/**
* 反序列化String类型的key值
* @author khy
* @createTime 2019年11月12日上午10:44:07
* @param bs
* @return
*/
public static String deserializeKey(byte[] bs) {
return keySerializer.deserialize(bs);
}
/**
* 反序列化String类型的value值
* @author khy
* @createTime 2019年11月12日上午10:44:07
* @param bs
* @return
*/
public static String deserializeStringValue(byte[] bs) {
return keySerializer.deserialize(bs);
}
/**
* 反序列化Object类型的value值
* @author khy
* @createTime 2019年11月12日上午11:38:21
* @param bs
* @return
*/
public static <V>V deserializeObjectValue(byte[] bs) {
return (V) valueSerializer.deserialize(bs);
}
/**
* 反序列化多个key值
* @author khy
* @createTime 2019年11月12日上午10:43:28
* @param rawValues
* @param type
* @return
*/
public static Set<String> deserializeKeys(Collection<byte[]> rawValues) {
Set<String>set = new LinkedHashSet<String>(rawValues.size());
for (byte[] bs : rawValues) {
set.add(deserializeKey(bs));
}
return set;
}
/**
* 批量反序列化成指定集合
* @author khy
* @createTime 2019年11月12日上午10:52:38
* @param rawValues
* @param type
* @return
*/
public static <T extends Collection<?>> T deserializeValues(Collection<byte[]> rawValues, Class<T> type) {
Collection<Object> values = List.class.isAssignableFrom(type) ? new ArrayList<Object>(rawValues.size()) : new LinkedHashSet<Object>(rawValues.size());
for (byte[] bs : rawValues) {
values.add(deserializeObjectValue(bs));
}
return (T) values;
}
/**
* 反序列化成Map集合
* @author khy
* @createTime 2019年11月13日下午2:59:20
* @param entries
* @return
*/
public static <V>Map<String, V> deserializeHashMap(Map<byte[], byte[]> entries) {
if (entries == null) {
return null;
}
Map<String, V> map = new LinkedHashMap<String, V>(entries.size());
for (Map.Entry<byte[], byte[]> entry : entries.entrySet()) {
map.put(deserializeKey(entry.getKey()),deserializeObjectValue(entry.getValue()));
}
return map;
}
}
总结
项目中通过RedisUtil工具类完成我们对不同数据类型的缓存数据操作的
设置key/value 时将不同类型的数据进行序列化存储.整套的代码已经全部在上面的demo 里面可以自行下载使用;基本不需要动什么配置,修改一下自己的缓存服务器地址.密码即可