1.非注解式实现
2.1使用之前要明确使用的业务场景
例如我们在登录时,可以让redis缓存验证码,又如在分类下显示菜品数据时,我们可以对分类和菜品进行缓存数据等等。
2.2导入Redis相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.3在使用的controller层导入RedisTemplate
例如:
说明一下:这里为什么使用@Resource注解而不使用@Autowired注解。
在Spring框架中,@Resource和@Autowired都是用来完成依赖注入的注解,它们可以将其他组件或者资源注入到当前的类中。在Spring框架中,@Resource和@Autowired都是用来完成依赖注入的注解,它们可以将其他组件或者资源注入到当前的类中。
@Resource是Java提供的一个通用注解,而@Autowired是Spring框架提供的注解。@Resource注解默认按照名称进行装配,通过name属性指定注入的目标对象名称。而@Autowired默认按照类型进行装配,它会自动根据类型选择合适的对象进行注入。另外,@Autowired注解可以配合@Qualifier注解一起使用,通过指定具体的bean名称来完成注入。
其次,@Resource可以用于注入任意的bean,包括其他类、接口、甚至是字符串等类型的资源。而@Autowired注解主要用于注入其他的bean对象。
此外,@Resource注解可以标注在字段、setter方法、构造方法和方法上,而@Autowired注解通常标注在字段和构造方法上。
在实践中,选择使用@Resource还是@Autowired取决于具体的需求和场景。如果需要按照名称进行注入,或者需要注入的对象是一个非Spring托管的对象,可以使用@Resource注解。如果只是简单的注入Spring托管的对象,并且希望按照类型自动选择合适的bean进行注入,可以使用@Autowired注解。
需要注意的是,@Resource和@Autowired注解都需要对应的类进行配置,以让Spring框架知道需要进行依赖注入的对象。
通过上面的说明,其实我们自己内心里已经有答案,孰强孰弱啦。
2.4此时,我们要配置Redis
2.4.1配置application.yml
2.4.2编写RedisConfig配置类
由于Redis是一个内存数据库,它将数据存储在内存中,因此需要将数据序列化为字节流进行存储。在将数据存入Redis或从Redis中取出数据时,需要进行序列化和反序列化的操作。
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定义RedisTemplate
* 设置Redis序列化方式,默认使用的是JDKSerializer的序列化方式,效率低,所以这里设置使用FastJsonRedisSerializer
*/
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置redis连接(LettuceConnectionFactory实现了RedisConnectionFactory)
redisTemplate.setConnectionFactory(connectionFactory);
FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
// key设置StringRedisSerializer序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// Hash key设置序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
可以参考一下,或许有更好的,大家可以借鉴一下。
2.5使用缓存(验证码为例)
此时我们可以测试一下,在此之前呢,怎么看缓存数据是一个问题,所以,安排一下Redis的可视化工具:
链接:https://pan.baidu.com/s/1OUNza9ea9fQepXqNTeTq-g
提取码:frpd
2.6测试
这只是一个简单的应用,然后我们再来一个其他的案例:缓存菜品数据
业务场景如下:
每个分类,比如湘菜,川菜,每次点击都需要再次重新查询数据库,不仅压力更大而且造成资源浪费,我们可以把这些查询的数据,按菜品分类给存入redis中,设置其30分钟生存周期,这样再次点击查看,就不会再查询数据库,直接从redis中获取数据,降低服务器压力也避免资源浪费。
缓存逻辑:
我们先动态构造唯一key值,然后根据key来获取value,接下来判断value是否为空,若不为空则表示redis中有该分类下的数据,直接返回;若为空则需要去数据库查询数据,然后再把查询的数据放入redis缓存中,下次再查询直接走redis缓存,不用再次查询数据库。
这个就不再演示了,到这里我们就可以明显觉得,代码量上来了,这只是一个查询都这样,再细想一下,这个查询会不会因为这个缓存出现问题,比如说我们新增了菜品,修改了菜品,删除了菜品,这个缓存区是不是得动一动,那这个重复的代码多不多,显而易见。
2.使用Spring Cache框架优化Redis缓存的过程
简单介绍一下这一位大咖:Spring Cache框架是Spring框架提供的一套基于注解的缓存解决方案,它在应用程序中简化了缓存操作的管理和使用。
Spring Cache框架的核心思想是通过在方法上添加缓存注解,来实现自动缓存的功能。它提供了一些常用的注解,如:
- @Cacheable:标注在方法上,表示该方法的返回结果可以被缓存,当方法被调用时,会首先检查缓存,如果缓存命中,则直接返回缓存中的结果,不再执行方法体中的逻辑。
- @CachePut:标注在方法上,表示该方法的返回结果需要更新缓存,每次方法被调用后,都会将返回结果更新到缓存中。
- @CacheEvict:标注在方法上,表示该方法会清除缓存中的数据,可以用于在更新或删除数据时清除相应的缓存。
2.1导入Spring Cache依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2.2启动类上加上注解开启缓存
2.3返回结果类实现序列化接口
2.4改造上一个案例的代码
不用意外,就是什么关于redis的什么都不剩了 ,我们只需要再控制层的接口上加上一个注解,就完事了。
2.5测试
测试后即会在redis中产生一个这样的目录结构
对照接口上的注解再理解一下你就会明白其中的意思了。
这个时候你和非注解方式对比你会发现一个问题,过期时间去哪啦,没法设置过期时间了!
3.再次优化Spring Cache使用
使用@Cacheable时,无法直接设置过期时间,需要自定义RedisCacheManager来实现ttl设置。
3.1编写TtlRedisCacheManager类来获取注解@Cacheable的参数
public class TtlRedisCacheManager extends RedisCacheManager {
public TtlRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
String[] cells = StringUtils.delimitedListToStringArray(name, "=");
name = cells[0];
if (cells.length > 1) {
long ttl = Long.parseLong(cells[1]);
// 根据传参设置缓存失效时间,默认单位是秒
cacheConfig = cacheConfig.entryTtl(Duration.ofMinutes(ttl));
}
return super.createRedisCache(name, cacheConfig);
}
}
3.2修改RedisConfig配置类
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定义RedisTemplate
* 设置Redis序列化方式,默认使用的是JDKSerializer的序列化方式,效率低,所以这里设置使用FastJsonRedisSerializer
*/
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置redis连接(LettuceConnectionFactory实现了RedisConnectionFactory)
redisTemplate.setConnectionFactory(connectionFactory);
FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
// key设置StringRedisSerializer序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
// Hash key设置序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
/**
* 实例化自定义的缓存管理器
*/
@Bean
@Primary
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(Objects.requireNonNull(redisTemplate.getConnectionFactory()));
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
return new TtlRedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
}
注意:项目中已配置了RedisCacheManager需要在原配置的bean上添加注解@Primary,以免造成干扰。
3.3修改controller层数据接口的注解
根据你在RedisCacheManager中设置的什么格式来填写value即可。
即完成对Redis缓存数据的使用。有什么问题还请留言。