springboot 集成redis 和http请求
springboot 集成redis ,使用原生的jedis ,有点繁琐,本身springboot 已经集成了 redis并有 redisTemplate 可以使用,不过还是多少有点坑,需要提前说明的
首先要引入jar包依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
然后在 application 配置文件中 配置redis 的连接项
spring.redis.database=0
spring.redis.host= 10.201.9.23
spring.redis.port=6379
spring.redis.password=88888
spring.redis.auth=88888
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.timeout=5000
接着最简单的使用就是
@Autowired
protected RedisTemplate<Object ,Object> redisTemplate;
或者
@Autowired
protected StringRedisTemplate redisTemplate;
如果你配置环境对的话,redis 就可以使用了
springboot 在启动会自己初始化 RedisConnectionFactory redisConnectionFactory
这个对象,然后注入 ,并初始化化一个 RedisTemplate 对象,这样感觉无缝连接到redis了,但是吧,平时没问题,一旦时间久了就会出问题,就是redis 的序列化和反序列化问题,之前没有在log 里捕捉 这个反序列化的异常,后来捕捉到这个异常,
ERROR] 2018-03-07 14:05:03,747 XXX - Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.StreamCorruptedException: invalid stream header: 6E756C6C
---------------------
作者:竹子鸠
来源:CSDN
原文:https://blog.csdn.net/yexiaojiu1/article/details/79470439
版权声明:本文为博主原创文章,转载请附上博文链接!
springboot在反序列话 redis,有点bug
如何破解 ,就是在初始化 RedisTemplate 这个bean 的时候就配置一下序列化和反序列化的属性,
声明一个 RedisService 公共类,并加 @Component 注解, 在这个里面初始化化 RedisTemplate,需要注意的是 就是你的key 对应的value存的是什么类型,如果是String
,就用new StringRedisSerializer(),如果是对象类 json ,就使用
new Jackson2JsonRedisSerializer(Object.class);或者
new GenericJackson2JsonRedisSerializer()),不然这个还会报错,
然后我们在这个里面 声明 get set exist remove redis key 的操作
最后使用 redis 的时候 ,直接注入 RedisService 就可以了
@Autowired
private RedisService redisService;
RedisService
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@Component
public class RedisService {
protected final Logger logger=LoggerFactory.getLogger(RedisService.class);
// @Autowired
// protected RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//RedisTemplate<String, String>
logger.info("尝试初始化redis template");
RedisTemplate<Object ,Object> redisTemplate= new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
//使用StringRedisSerializer来序列化和反序列化redis的key值
redisTemplate.setKeySerializer(new StringRedisSerializer());
// redisTemplate.setValueSerializer(serializer);
redisTemplate.setStringSerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
// redisTemplate.setEnableDefaultSerializer(true);
// redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
logger.info("redis init successful 初始化成功");
this.redisTemplate=redisTemplate;
return this.redisTemplate;
}
@Autowired
protected RedisTemplate<Object ,Object> redisTemplate;
/**
* 写入redis缓存(不设置expire存活时间)
* @param key
* @param value
* @return
*/
public boolean set(final String key, String value){
boolean result = false;
try {
logger.info("正在insert设置 "+key+"的redis 值"+value);
ValueOperations operations =redisTemplate.opsForValue();
operations.set(key, value);
result = true;
logger.info(key+" 插入redis 成功 "+value);
} catch (Exception e) {
logger.error("写入redis缓存失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* 写入redis缓存(设置expire存活时间)
* @param key
* @param value
* @param expire
* @return
*/
public boolean set(final String key, String value, Long expire){
boolean result = false;
try {
logger.info("正在设置 "+key+"的redis 值"+value+" expire "+expire);
ValueOperations operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
result = true;
logger.info(key+" 插入redis 成功 "+value);
} catch (Exception e) {
logger.error("写入redis缓存(设置expire存活时间)失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* 读取redis缓存
* @param key
* @return
*/
public Object get(final String key){
Object result = null;
try {
logger.info("正在尝试获取 "+key+"的redis 值");
ValueOperations operations = redisTemplate.opsForValue();
result = operations.get(key);
logger.info("get 得到 "+key+"的redis 值"+result);
} catch (Exception e) {
logger.error("读取redis缓存失败!错误信息为:" + e.getMessage());
String connect=redisTemplate.getConnectionFactory().getConnection().toString();
logger.error(connect);
}
return result;
}
/**
* 判断redis缓存中是否有对应的key
* @param key
* @return
*/
public boolean exists(final String key){
boolean result = false;
try {
logger.info("正在查看 "+key+"的redis 值 是否存在");
result = redisTemplate.hasKey(key);
logger.info("查看 "+key+"的redis 值 存在 结果 "+result);
} catch (Exception e) {
logger.error("判断redis缓存中是否有对应的key失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* redis根据key删除对应的value
* @param key
* @return
*/
public boolean remove(final String key){
boolean result = false;
try {
if(exists(key)){
logger.info("移除 "+key+"的redis 值");
redisTemplate.delete(key);
}
result = true;
} catch (Exception e) {
logger.error("redis根据key删除对应的value失败!错误信息为:" + e.getMessage());
}
return result;
}
/**
* redis根据keys批量删除对应的value
* @param keys
* @return
*/
public void remove(final String... keys){
for(String key : keys){
remove(key);
logger.info("remove redis key "+key);
}
}
}
}
另外 springboot 请求外部http的时候使用 RestTemplate 也有一个坑,就是默认的request buffer不释放,导致时间越久,请求头巨大,最后 就无法请求外部了,所以 可以这样使用
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
@Component
public class RestHttpConfig {
@Bean
public RestTemplate restTemplate(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setBufferRequestBody(false);
RestTemplate restTemplate = new RestTemplate(factory);
MappingJackson2HttpMessageConverter jsonHttpMessageConverter = new MappingJackson2HttpMessageConverter(); jsonHttpMessageConverter.getObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
restTemplate.getMessageConverters().add(jsonHttpMessageConverter);
return restTemplate;
}
}