金麟岂是池中物,一遇风云便化龙
微服务如今的发展趋已然是势不可挡,并且业内已经有Dubbo、SpringCloud等优秀的开源框架,可以说发展的已经是非常成熟了,所以决定顺应技术发展浪潮,放弃老旧而臃肿的SSM,转而搭建以SpringCloud为基础的微服务应用。
通过Redis实现缓存与应用集群间的Session共享是很成熟的应用缓存层解决方案,所以在框架搭建过程中必然是需要整合Redis,并且通过Redis的Sentinel实现了Redis的高可用。在整合Redis的过程中始终没有找到比较好用的解决方案,看过很多博客,发现都不是自己想要的,所以索性决定自己来写一个,仅供参考。
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>2.9.0version>
dependency>
虽然SpringCloud简化项目配置,但是绝对不是要求研发人员在项目中不可以使用配置,还是那句话约定大于配置,习惯大于约定。所以我们在项目中建立redis.properties用于配置Redis服务。
redis.nodes=192.168.1.205:26379,192.168.1.206:26379,192.168.1.207:26379
redis.masterName=artisanRedis
redis.password=abc123456
redis.maxTotal=10000
redis.maxIdle=100
redis.minIdle=50
redis.timeout=30000
SpringCloud给我们带了很多开箱即用的工具,能够让我们的代码更加的优雅。@ConfigurationProperties 让我们不再为读取配置文件而感到烦恼,在SpringBoot 1.5+后需要配合@PropertySource使用,RedisConfig.java便优雅的读取了Redis配置文件。
package com.artisan.redis.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午6:25
* Redis配置文件
*
*/
@Component
@PropertySource("classpath:conf/redis.properties")
@ConfigurationProperties(prefix = "redis")
public class RedisConfig {
/**
* 节点名称
*/
private String nodes;
/**
* Redis服务名称
*/
private String masterName;
/**
* 密码
*/
private String password;
/**
* 最大连接数
*/
private int maxTotal;
/**
* 最大空闲数
*/
private int maxIdle;
/**
* 最小空闲数
*/
private int minIdle;
/**
* 连接超时时间
*/
private int timeout;
public String getNodes() {
return nodes;
}
public void setNodes(String nodes) {
this.nodes = nodes;
}
public String getMasterName() {
return masterName;
}
public void setMasterName(String masterName) {
this.masterName = masterName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
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 getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
@Override
public String toString() {
return "RedisConfig{" +
"nodes='" + nodes + '\'' +
", masterName='" + masterName + '\'' +
", password='" + password + '\'' +
", maxTotal='" + maxTotal + '\'' +
", maxIdle='" + maxIdle + '\'' +
", minIdle='" + minIdle + '\'' +
", timeout='" + timeout + '\'' +
'}';
}
}
简约配置问风格让我们不能再像从前一样,随心所欲的在Spring.xml文件中实例化某个Bean,但是注解@Bean却为我们打开了一扇窗。RedisInitConfig.java文件中创建了JedisPoolConfig,JedisSentinelPool这两个重要的对象,为后面RedisService对外提供Jedis奠定了基础。
package com.artisan.redis.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午6:28
* redis初始化配置
*
*/
@Configuration
public class RedisInitConfig {
/**
* 日志打印对象
*/
private Logger log = LoggerFactory.getLogger(RedisInitConfig.class);
/**
* 注入配置文件信息
*/
@Autowired
private RedisConfig redisConfig;
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午6:53
* @return redis.clients.jedis.JedisPoolConfig
* 初始化连接池配置对象
*
*/
@Bean(value = "jedisPoolConfig")
public JedisPoolConfig initJedisPoolConfig(){
log.info("JedisPool initialize start ...");
JedisPoolConfig config = new JedisPoolConfig();
//最大总量
config.setMaxTotal(redisConfig.getMaxTotal());
//设置最大空闲数量
config.setMaxIdle(redisConfig.getMaxIdle());
//设置最小空闲数量
config.setMinIdle(redisConfig.getMinIdle());
//常规配置
config.setTestOnBorrow(true);
config.setTestOnReturn(true);
log.info("JedisPool initialize end ...");
return config;
}
/**
*
* @author Fire Monkey
* @date 下午7:20
* @return redis.clients.jedis.JedisSentinelPool
* 生成JedisSentinelPool并且放入Spring容器
*
*/
@Bean(value = "sentinelPool")
public JedisSentinelPool initJedisPool(@Qualifier(value = "jedisPoolConfig") JedisPoolConfig jedisPoolConfig){
Set nodeSet = new HashSet<>();
//获取到节点信息
String nodeString = redisConfig.getNodes();
//判断字符串是否为空
if(nodeString == null || "".equals(nodeString)){
log.error("RedisSentinelConfiguration initialize error nodeString is null");
throw new RuntimeException("RedisSentinelConfiguration initialize error nodeString is null");
}
String[] nodeArray = nodeString.split(",");
//判断是否为空
if(nodeArray == null || nodeArray.length == 0){
log.error("RedisSentinelConfiguration initialize error nodeArray is null");
throw new RuntimeException("RedisSentinelConfiguration initialize error nodeArray is null");
}
//循环注入至Set中
for(String node : nodeArray){
log.info("Read node : {}。" , node);
nodeSet.add(node);
}
//创建连接池对象
JedisSentinelPool jedisPool = new JedisSentinelPool(redisConfig.getMasterName() ,nodeSet ,jedisPoolConfig ,redisConfig.getTimeout() , redisConfig.getPassword());
return jedisPool;
}
}
前面已经将JedisSentinelPool实例化,RedisService只需要将该对象注入,通过JedisSentinelPool获取到Jedis,对外提供缓存服务,至此SpringCloud整合Jedis结束。
package com.artisan.redis.service;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.exceptions.JedisConnectionException;
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:32
* Reids工具通过Jedis实现与Redis交互
*
*/
@Component
public class RedisService {
/**
* 日志打印对象
*/
private static Logger log = Logger.getLogger(RedisService.class);
/**
* Jedis对象池 所有Jedis对象均通过该池租赁获取
*/
private static JedisSentinelPool sentinelPool;
/**
* 缓存数据成功
*/
private final static String CACHE_INFO_SUCCESS = "OK";
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:34
* 注入JedisSentinelPool
*
*/
@Autowired
public void setSentinelPool(JedisSentinelPool sentinelPool) {
RedisService.sentinelPool = sentinelPool;
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:35
* @return redis.clients.jedis.Jedis
* 获取到Jedis
*
*/
private static Jedis getJedis() {
Jedis jedis;
try {
jedis = sentinelPool.getResource();
return jedis;
} catch (JedisConnectionException e) {
log.error("获取Redis 异常", e);
throw e;
}
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:36
* 缓存String类型的数据,数据不过期
*
*/
public static boolean setString(String key, String value) throws Exception {
return setString(key, value, -1);
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:40
* 缓存String类型的数据并设置超时时间
*
*/
public static boolean setString(String key, String value, int timeout) throws Exception {
String result;
Jedis jedis = null;
try {
jedis = getJedis();
result = jedis.set(key, value);
if (timeout != -1) {
jedis.expire(key, timeout);
}
if (CACHE_INFO_SUCCESS.equals(result)) {
return true;
} else {
return false;
}
} finally {
releaseRedis(jedis);
}
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:46
* 获取String类型的数据
*
*/
public static String getString(String key) throws Exception {
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.get(key);
} catch (Exception e) {
throw e;
} finally {
releaseRedis(jedis);
}
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:49
* @return void
* 释放Jedis
*
*/
public static void releaseRedis(Jedis jedis) {
if (jedis != null) {
jedis.close();
}
}
/**
*
* @author Fire Monkey
* @date 2018/3/12 下午7:55
* @return boolean
* 通过key删除缓存中数据
*
*/
public static boolean del(String key) throws Exception {
Long num;
Jedis jedis = null;
Boolean result = false;
try {
jedis = getJedis();
num = jedis.del(key);
if (num.equals(1L)) {
result = true;
}
}finally {
releaseRedis(jedis);
}
return result;
}
}
github传送门:[email protected]:MarsMuse/ArtisanCloud.git
这是作者从业来的第一篇博客,写的不好的地方还请各位见谅,如果这篇博客能够为您带来哪怕是丝毫帮助,我也深感荣幸。