SpringBoot与Redis整合
今天在做spring boot和redis整合时,出现了JedisConnectionFactory无法实现自动注入的错误:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.redis.connection.jedis.JedisConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1509)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1065)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:584)
... 81 more
附上我引入的redis相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
application.yml文件的相关配置:
spring:
redis:
database: 1
host: 127.0.0.1
password:
port: 6379
timeout: 10000 #毫秒
jedis:
pool:
max-active: 8 #连接池最大连接数
max-idle: 8 #连接池最大空闲连接
max-wait: -1 #连接池最大阻塞等待时间,负值表示无限制
min-idle: 0 #连接池最小空闲连接
还有Redis配置类的代码:
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private JedisConnectionFactory jedisConnectionFactory;
/**
* 主键 key生成策略
*/
// @Override
// public KeyGenerator keyGenerator() {
// return super.keyGenerator();
// }
/**
* 缓存管理器
*/
@Bean
public CacheManager cacheManager(JedisConnectionFactory jedisConnectionFactory) {
return RedisCacheManager.create(jedisConnectionFactory);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory);
setSerializer(redisTemplate);
return redisTemplate;
}
/**
* 设置序列化方式
*/
private void setSerializer(RedisTemplate redisTemplate) {
// 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
//该方法在使用redisTemplate之前执行,完成初始化
redisTemplate.afterPropertiesSet();
}
}
最后是我的测试代码:
@RunWith(SpringRunner.class)
@SpringBootTest
public class testRedis {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
//存入字符串
@Test
public void putString() {
redisTemplate.opsForValue().set("dk", "123");
redisTemplate.opsForValue().set("dk", "999", 100, TimeUnit.SECONDS);
}
}
在经过一番网上的搜索和查阅spring boot相关资料后,发现原来我们在引入spring-boot-starter-redis依赖的时候,它自动帮我们引入了lettuce的依赖:
这个lettuce取代了jedis作为redis的驱动,如果我们仍然要用jedis的话,就必须要先排除lettuce的依赖包,再加入jedis的依赖包,具体如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<artifactId>lettuce-core</artifactId>
<groupId>io.lettuce</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
最后再次测试,运行顺利,问题解决.
那么这个Lettuce到底是什么呢?
Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型.
Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接.
Lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问。