SpringBoot2.0集成Redis
首先安装的过程就不提了。上一个项目的redis是配置在Windows下的,集成很简单,也没有做什么配置。这次为了进行测试,装在了linux下。在SpringBoot集成的过程中遇到了一些小坑,分享一下。
pom文件中添加依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--引入Json依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
可以看到除了Redis我还加入了JSON的依赖,这是因为我之后读取出来的数据要转换成JSON串的格式,数据可读,方便开发。
application.properties文件中添加配置
#redis配置
#Linux主机地址
spring.redis.host=192.168.78.131
#端口
spring.redis.port=6379
#超时时间,ms
spring.redis.timeout=3000
#连接池的最大连接数
spring.redis.jedis.pool.max-active=10
#链接的最大等待时间ms
spring.redis.jedis.pool.max-wait=3000
#连接池中的最大的等待数量
spring.redis.jedis.pool.max-idle=10
在SpringBoot2.0的版本中timeout变成了Duration类型的,从其源码中我们可以看一下是怎么定义的:
public void setTimeout(Duration timeout) {
this.timeout = timeout;
}
所以正常的写法应该是:
spring.redis.timeout=3000ms
但是这样也带来了一个问题,下面再说这个问题是什么,这里先按照初始的定义,不会报错的
正常的人可能还会在配置文件中添加redis的密码的配置,没有密码的话就不要添加这个配置,就算默认为空也会导致出现错误,不能实现OAuth认证,要是有密码的话就添加上并写上自己的密码。
spring.redis.password=
Redis的自定义初始化
首先写redisConfig的文件,读取application.properties文件中yml的配置
package com.springboot.SecKill.redis;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* Redis的配置
* @author WilsonSong
* @date 2018/8/1/001
*/
//作为组件扫描进来
@Component
//读取配置文件
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
public class RedisConfig {
private String host; //主机
private int port; //端口
private int timeout; //超时时间
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive; //连接池最大线程数
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWait; //等待时间
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;//最大空闲连接
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public long getMaxWait() {
return maxWait;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public int getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
}
上面用了两种方式来读取application.properties中的配置,一种是直接设置@ConfigurationProperties(prefix = “spring.redis”),然后变量名与application.properties中的变量名一样,这样就可以读出来了,然后像max-wait这种变量名没法定义啊,所以又用了@Value(“${spring.redis.jedis.pool.max-idle}”)这种注解的方式来读取,当然你可以全部影注解的方式来读取,注意过程中的每一个变量的基本数据类型定义准确。maxWait和timeout这两个本来都是Duration类型的,但是这里分别写成long和int类型的。一会儿再解释这个问题。
过程中需要从redis连接池中获取redis服务,所以这里初始化jedisPool的配置
package com.springboot.SecKill.redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @author WilsonSong
* @date 2018/8/1/001
*/
@Service
public class RedisPoolFactory {
@Autowired
RedisConfig redisConfig;
/**
* redis连接池的一些配置
* @return
*/
@Bean
public JedisPool JedisPoolFactory(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisConfig.getMaxIdle());
poolConfig.setMaxTotal(redisConfig.getMaxActive());
poolConfig.setMaxWaitMillis((redisConfig.getMaxWait()));
JedisPool jedisPool = new JedisPool(poolConfig, redisConfig.getHost(),redisConfig.getPort(),redisConfig.getTimeout());
return jedisPool;
}
}
这里解释下maxWait和timeout这两个数据类型的问题。首先
poolConfig.setMaxWaitMillis((redisConfig.getMaxWait()));
用到了maxWait这个变量,看一下setMaxWaitMillis()函数的源码
public void setMaxWaitMillis(long maxWaitMillis) {
this.maxWaitMillis = maxWaitMillis;
}
maxWaitMillis这个变量是long类型的,所以执勤才那么定义。
同理
JedisPool jedisPool = new JedisPool(poolConfig, redisConfig.getHost(),redisConfig.getPort(),redisConfig.getTimeout());
这里面有用到redisConfig.getTimeout(),看一下JedisPool是怎么初始化的
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port, int timeout) {
this(poolConfig, host, port, timeout, (String)null, 0, (String)null);
}
可以看到timeout是int类型的,你要一开始定义成Duration类型的,然后可能过程中会涉及到数据类型的强制准换,会不会报错不知道,有兴趣的可以试一下。
最后就是初始化redis的方法如get,set等等
package com.springboot.SecKill.redis;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* @author WilsonSong
* @date 2018/8/1
*/
@Service
public class RedisService {
private static final Logger logger = LoggerFactory.getLogger(RedisService.class);
@Autowired
JedisPool jedisPool;
public <T> T get(KeyPrefix prefix, String key, Class<T> clazz){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
//生成real key
String realKey = prefix.getPrefix() + key;
String str = jedis.get(realKey);
T t = String2Bean(str, clazz);
return t;
}catch (Exception e){
logger.error("redis连接池异常"+e.getMessage());
return null;
}finally {
if (jedis != null){
jedis.close();
}
}
}
public <T> boolean set(KeyPrefix prefix,String key, T value){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
String value_new = Bean2String(value);
if (value_new == null || value_new.length() <0){
return false;
}
//生成real key
String realKey = prefix.getPrefix() + key;
//过期时间
int seconds = prefix.expireSeconds();
if (seconds <= 0){
jedis.set(realKey, value_new);
}else {
jedis.setex(realKey,seconds,value_new);
}
return true;
}catch (Exception e){
logger.error("redis连接池异常"+e.getMessage());
return false;
}finally {
if (jedis != null){
jedis.close();
}
}
}
//key 是否存在
public <T> Boolean exists(KeyPrefix prefix, String key){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
//生成real key
String realKey = prefix.getPrefix() + key;
return jedis.exists(realKey);
}catch (Exception e){
logger.error("redis连接池异常"+e.getMessage());
return null;
}finally {
if (jedis != null){
jedis.close();
}
}
}
//增加key对应的值
public <T> Long incr(KeyPrefix prefix, String key){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
//生成real key
String realKey = prefix.getPrefix() + key;
return jedis.incr(realKey);
}catch (Exception e){
logger.error("redis连接池异常"+e.getMessage());
return null;
}finally {
if (jedis != null){
jedis.close();
}
}
}
//减少key对应的对象的值
public <T> Long decr(KeyPrefix prefix, String key){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
//生成real key
String realKey = prefix.getPrefix() + key;
return jedis.decr(realKey);
}catch (Exception e){
logger.error("redis连接池异常"+e.getMessage());
return null;
}finally {
if (jedis != null){
jedis.close();
}
}
}
//bean对象准换为String
private <T> String Bean2String(T value) {
if (value == null){
return null;
}
Class<?> clazz = value.getClass();
if (clazz == int.class || clazz == Integer.class){
return ""+value;
}else if (clazz == String.class){
return (String)value;
}else if (clazz == long.class || clazz == Long.class){
return ""+value;
}else {
return JSON.toJSONString(value);
}
}
//String转换为bean
private <T> T String2Bean(String str, Class<T> clazz) {
if (str == null || str.length() <0 || clazz == null){
return null;
}
if (clazz == int.class || clazz == Integer.class){
return (T)Integer.valueOf(str);
}else if (clazz == String.class){
return (T)str;
}else if (clazz == long.class || clazz == Long.class){
return (T)Long.valueOf(str);
}else {
return JSON.toJavaObject(JSON.parseObject(str),clazz);
}
}
}
最后在controller中编写一个方法实现对service层的调用即可,就不赘述了。
踩过的坑
运行程序发现报出异常
Could not get a resource from the pool。
其实也就是在执行
jedis = jedisPool.getResource();这一步时出错了
- 首先第一种可能是你的redis服务没开启,检查下。
- 确认开启了之后就修改你的redis.conf文件,把bind 127.0.0.1改成bind 0.0.0.0,
也就是把redis的访问权限有只能本机访问改成所有的都能访问。
- 最后可能的原因有你的Linux的防火墙没有开放Redis的端口,可以配置打开,也可以直接关掉防火墙,我这里直接关掉了Linux的防火墙。
我用的是centos7
永久关闭防火墙的方法
//临时关闭
systemctl stop firewalld
//禁止开机启动
systemctl disable firewalld
这样你再测试下,要是还不能用还有别的原因,可以自己上网去看一下具体怎么解决。