Blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

springboot-redis

发表于 2019-08-23 更新于 2019-08-24 分类于 SpringBoot 阅读次数:
本文字数: 8.3k

环境搭建

依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
1
2
3
4
5
6
7
@SpringBootApplication
@EnableCaching
public class SpringbootRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootRedisApplication.class, args);
}
}

controller

1
2
3
4
5
6
7
8
9
10
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/user/{id}")
public User getUserById(@PathVariable("id") int id){
User user = userService.getUserById(id);
return user;
}
}

service

1
2
3
4
5
6
7
8
9
10
11
@Service
public class UserService {
@Autowired
private UserMapper userMapper;

@Cacheable(cacheNames = "user",key = "#id")
public User getUserById(int id) {
User user = userMapper.getUserById(id);
return user;
}
}

mapper

1
2
3
4
5
@Mapper
public interface UserMapper {
@Select("select * from user where id = #{id}")
User getUserById(int id);
}

只要在启动类上加一个@EnableCaching注解就可以,关于@Cacheable,@CachePut,@CacheEvict,@Caching等注解在上一篇(springboot-cache)中已经解释过了。

测试

此时会报一个异常,这是由于User类没有实现序列化。给User实现一个Serializable接口,再进行测试。

1
2
3
4
5
6
7
8
9
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Data
public class User implements Serializable{
private int id;
private String name;
private int age;
}

此时没有报错了,也成功加入缓存中了。但是查看一个redis,发现。

这是由于默认使用的是JdkSerializationRedisSerializer,我们可以自定义序列化方式

自定义序列化方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Configuration
public class RedisConfig extends CachingConfigurerSupport {

@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial()))
.entryTtl(Duration.ofSeconds(3000L))
.disableCachingNullValues();

RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.transactionAware()
.build();
return cacheManager;
}

public Jackson2JsonRedisSerializer jacksonSeial() {
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
return jacksonSeial;
}
}

配置完之后,再来测试一下,先将之前的缓存清除一下。结果如下

源码分析

springboot在启动的时候,会自动装配一些配置类,详情参考(”springboot启动配置原理”这篇文章),引入了redis依赖后,只要我们加上了@EnableCaching注解后,CacheAutoConfiguration就能成功注入到ioc容器中,RedisAutoConfiguration也能成功注入到容器中,不加的话就不会注入到容器中。

RedisAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}

注入了RedisTemplate,就可以使用RedisTemplate来操作redis数据库。其中还有个RedisProperties类,其中有配置了很多redis相关的默认属性,所以一般就不需要我们在配置文件中写常用的一些属性了。

CacheAutoConfiguration

1
2
3
4
5
6
7
8
9
10
@Configuration
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
public class CacheAutoConfiguration {}

CacheConfigurationImportSelector

1
2
3
4
5
6
7
8
9
10
11
12
static class CacheConfigurationImportSelector implements ImportSelector {

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for (int i = 0; i < types.length; i++) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}

这里会导入一些有关缓存的配置类

其中默认生效的是SimpleCacheConfiguration,详情参考(”spingboot-cache”这篇文章),但是我们加入了redis有关的依赖后,默认生效的就是RedisCacheConfiguration(这里自定义一个RedisConfig了之后,生效的有好几个,不知道为什么。。。)了。可以运行一下看看(在配置文件中加入debug: true)

RedisCacheConfiguration(org.springframework.boot.autoconfigure.cache)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class RedisCacheConfiguration {

private final CacheProperties cacheProperties;

private final CacheManagerCustomizers customizerInvoker;

private final org.springframework.data.redis.cache.RedisCacheConfiguration redisCacheConfiguration;

RedisCacheConfiguration(CacheProperties cacheProperties,
CacheManagerCustomizers customizerInvoker,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration) {
this.cacheProperties = cacheProperties;
this.customizerInvoker = customizerInvoker;
this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
}

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
return this.customizerInvoker.customize(builder.build());
}

private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
ClassLoader classLoader) {
if (this.redisCacheConfiguration != null) {
return this.redisCacheConfiguration;
}
Redis redisProperties = this.cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
.defaultCacheConfig();
config = config.serializeValuesWith(SerializationPair
.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}

这里会注入一个RedisCacheManager,这里会设置一个默认的配置:cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()))
determineConfiguration是org.springframework.data.redis.cache.RedisCacheConfiguration类型的。

RedisCacheConfiguration(org.springframework.data.redis.cache)

1
2
3
4
5
6
7
8
9
10
11
12
public class RedisCacheConfiguration {

private final Duration ttl;
private final boolean cacheNullValues;
private final CacheKeyPrefix keyPrefix;
private final boolean usePrefix;

private final SerializationPair<String> keySerializationPair;
private final SerializationPair<Object> valueSerializationPair;

private final ConversionService conversionService;
}

这里RedisCacheConfiguration主要配置缓存的序列化方式,时间等属性。

gitee:demo

github:demo


------ 已触及底线感谢您的阅读 ------
麻辣香锅不要辣 微信支付

微信支付

  • 本文作者: 麻辣香锅不要辣
  • 本文链接: https://http://ybhub.gitee.io/2019/08/23/springboot-redis/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
# SpringBoot # Cache
springboot-----cache
springboot-rabbitmq
  • 文章目录
  • 站点概览
麻辣香锅不要辣

麻辣香锅不要辣

21 日志
11 分类
20 标签
GitHub 简书
  1. 1. 环境搭建
  2. 2. 测试
  3. 3. 自定义序列化方式
  4. 4. 源码分析
    1. 4.1. RedisAutoConfiguration
    2. 4.2. CacheAutoConfiguration
    3. 4.3. CacheConfigurationImportSelector
    4. 4.4. RedisCacheConfiguration(org.springframework.boot.autoconfigure.cache)
    5. 4.5. RedisCacheConfiguration(org.springframework.data.redis.cache)
© 2019 – 2020 麻辣香锅不要辣 | 站点总字数: 20.4k字
|
0%