本文从概念是实操的角度说明了redis和spring的集成。第一章节摘自网络,这里转发了。
java编程接口
本章节来自网络。原文链接:
https://www.cnblogs.com/mcbye/p/Jedis-VS-Redisson.html
概况对比
Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
编程模型
Jedis中的方法调用是比较底层的暴露的Redis的API。
而Redisson中的方法则是进行比较高的抽象。
可伸缩性
Jedis其方法调用都是同步的。Jedis客户端实例不是线程安全的。
Redisson其方法调用是异步的。Redisson的API是线程安全的。
数据结构
Jedis仅支持基本的数据类型如:String、Hash、List、Set、Sorted Set。
Redisson不仅提供了一系列的分布式Java常用对象,基本可以与Java的基本数据结构通用,还提供了许多分布式服务,其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)。在分布式开发中,Redisson可提供更便捷的方法。
spring集成示例
spring为缓存提供了更加抽象的接口:Cache和CacheManager。
redisson依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.5.7</version>
</dependency>
spring-redis 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>
两种依赖选择一种就好。他们分别是redisson和spring-jedis的控制接口。
redisson
如果采用redisson作为底层的client,配置如下:
@Configuration
@EnableCaching
public class WebConfiguration {
@Autowired
RedisProperties redisProperties;
@Value("${spring.redis.mode}")
String cacheMode;
@Value("${spring.redis.sentinel-addrs}")
String sentinelAddrs;
@Value("${spring.redis.sentinel-masterName}")
String sentinelMasterName;
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() throws IOException {
Config config = new Config();
switch (cacheMode) {
case "single":
config.useSingleServer().setAddress(redisProperties.getHost() +
":" + redisProperties.getPort())
.setPassword(redisProperties.getPassword()).setDatabase(redisProperties.getDatabase());
break;
case "sentinel":
String[] sentinels = sentinelAddrs.split(",");
if (Strings.isNullOrEmpty(redisProperties.getPassword())) {
config.useSentinelServers().addSentinelAddress(sentinels).setMasterName(sentinelMasterName).setDatabase(redisProperties.getDatabase());
} else {
config.useSentinelServers().addSentinelAddress(sentinels).setMasterName(sentinelMasterName)
.setPassword(redisProperties.getPassword()).setDatabase(redisProperties.getDatabase());
}
break;
default:
break;
}
return Redisson.create(config);
}
/**
* 构建CacheManager
* @param redissonClient Redisson客户端
*/
@Bean
public CacheManager cacheManager(RedissonClient redissonClient) {
CacheManager cacheManager = new
RedissonSpringCacheManager(redissonClient);
return cacheManager;
}
}
对应的配置文件:
spring:
redis:
mode: sentinel
sentinel-<u>addrs</u>:
localhost:26377,localhost:26378,localhost:26379
sentinel-masterName: master
database: 1
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
timeout: 0
jedis
和redisson相比,jedis需要配置连接池。但是顶层接口依然是Cache和CacheManager。
@Bean
public CacheManager jedisCacheManager(RedisTemplate<String, Object>
template) {
RedisCacheManager cacheManager = new RedisCacheManager(template);
return cacheManager;
}
@Bean
public RedisConnectionFactory factory() {
JedisConnectionFactory jedisConnectionFactory = null;
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(redisProperties.getPool().getMaxIdle());
poolConfig.setMinIdle(redisProperties.getPool().getMinIdle());
poolConfig.setMaxTotal(redisProperties.getPool().getMaxActive());
poolConfig.setMaxWaitMillis(redisProperties.getPool().getMaxWait());
switch (cacheMode) {
case "single":
jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
jedisConnectionFactory.setHostName(redisProperties.getHost());
jedisConnectionFactory.setPort(redisProperties.getPort());
jedisConnectionFactory.setPassword(redisProperties.getPassword());
jedisConnectionFactory.setDatabase(redisProperties.getDatabase());
break;
case "sentinel":
RedisSentinelConfiguration sentinelConfig = new
RedisSentinelConfiguration();
Set<RedisNode> redisNodeSet = new HashSet<>();
String[] sentinels = sentinelAddrs.split(",");
for (String sentinel : sentinels) {
String[] node = sentinel.split(":");
RedisNode redisNode = new RedisNode(node[0],
Integer.valueOf(node[1]));
redisNodeSet.add(redisNode);
}
sentinelConfig.setSentinels(redisNodeSet);
sentinelConfig.setMaster(sentinelMasterName);
jedisConnectionFactory = new
JedisConnectionFactory(sentinelConfig, poolConfig);
jedisConnectionFactory.setDatabase(redisProperties.getDatabase());
break;
default:
break;
}
return jedisConnectionFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory
factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String,
Object>();
redisTemplate.setConnectionFactory(factory);
return redisTemplate;
}
properties配置文件和redisson是一样的。
spring 自动配置
前面讲的是手动配置,但是spring-boot提供了自动配置。按照要求在properties中设置参数,就会自动完成配置。
我们可以查看spring-boot-autoconfigure 中的RedisAutoConfiguration
@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
/**
* Redis connection configuration.
*/
@Configuration
@ConditionalOnClass(GenericObjectPool.class)
protected static class RedisConnectionConfiguration {
private final RedisProperties properties;
private final RedisSentinelConfiguration sentinelConfiguration;
private final RedisClusterConfiguration clusterConfiguration;
public RedisConnectionConfiguration(RedisProperties properties,
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
this.properties = properties;
this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
}
//在没有配置RedisConnectionFactory的情况下,根据参数初始化连接池
@Bean
@ConditionalOnMissingBean(RedisConnectionFactory.class)
public JedisConnectionFactory redisConnectionFactory()
throws UnknownHostException {
return applyProperties(createJedisConnectionFactory());
}
//省略细节
.
.
.
.
}
/**
* Standard Redis configuration.
*/
@Configuration
protected static class RedisConfiguration {
//在没有定义RedisTemplate的情况下,定义redisTemplate
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
//在没有定义StringRedisTemplate的情况下,初始化StringRedisTemplate的bean
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
}
通过配置我们可以看到其实自动配置已经包含了redis链接的初始化。底层采用jedis客户端。默认实现两个template:RedisTemplate以及StringRedisTemplate。我们在自己的配置文件中定义CacheManager即可。
通过代码可以看出,配置支持哨兵和集群。如果两者都配置,则采用哨兵的配置信息。
private JedisConnectionFactory createJedisConnectionFactory() {
JedisPoolConfig poolConfig = this.properties.getPool() != null ? jedisPoolConfig() : new JedisPoolConfig();
if (getSentinelConfig() != null) {
return new
JedisConnectionFactory(getSentinelConfig(), poolConfig);
}
if (getClusterConfiguration() != null) {
return new
JedisConnectionFactory(getClusterConfiguration(), poolConfig);
}
return new JedisConnectionFactory(poolConfig);
}
默认的配置信息,存储在RedisProperties中,通过RedisProperties的属性,我们可以看出配置文件的配置格式:
spring:
redis:
database:
host:
password:
port:
timeout:
pool:
maxIdle:
minIdle:
maxActive:
maxWait:
sentinel:
master:
nodes:
cluster:
nodes:
maxRedirects:
多缓存配置
这个业务需求来源是,有些数据需要定时更新,有些数据则有外部触发的时候才更新。
定时更新,可以采用timer定期触发更新,但是需要依赖quartz。同时,在没有外部调用的时候,还浪费资源。所以想采用过期策略,实现缓存数据的定期更新。
多缓存配置
多缓存,只要在Config中配置多个CacheManager即可。client链接配置保持不变。
@Bean
public CacheManager cacheManager(RedissonClient redissonClient) {
CacheManager cacheManager = new
RedissonSpringCacheManager(redissonClient);
return cacheManager;
}
@Bean
public CacheManager jedisCacheManager(RedisTemplate<String, Object>
template) {
RedisCacheManager cacheManager = new RedisCacheManager(template);
return cacheManager;
}
//配置cache:timeoutCache,且超时时间为60s
@Bean
public CacheManager timeoutCacheManager(RedisTemplate<String, Object>
template) {
RedisCacheManager cacheManager = new RedisCacheManager(template);
Map<String, CacheConfig> config = new HashMap<>();
config.put("timeoutCache", new CacheConfig(60*1000, 10*1000));
cacheManager.setConfig(config);
return cacheManager;
}
多缓存使用
首先需要配置缓存生效,为config类添加@EnableCaching注解。
然后在接口上声明@Cacheable。
实例如下:
@Service
public class CacheService {
@Cacheable(cacheNames = "timeoutCache", cacheManager = "timeoutCacheManager", key = "T(com.yunzhong.static.MyStaticClass).MY_KEY"
public String getMessage(){
return dao.getFromDB();
}
}
key = "T(com.yunzhong.static.MyStaticClass).MY_KEY"表示了缓存key的生成方式,这里采用spel从静态属性获取。