目录
为什么要用缓存
代码实现
自定义注解
aop逻辑实现
Controller控制层使用
实现效果
Sprting Cache
Spring Cache简介
Spring Cache使用效果
缓存注解
Cacheable注解
在线博客系统SpringCache使用
编码实现
pop依赖
application.properties配置文件
启动类开启缓存注解
CacheConfig配置文件
缓存注解实现
效果展示
为什么要用缓存
- 如果用户 A 打开 APP,进入到了秒杀商品的详情页,那这个商品数据我们会先去数据库查询,然后返回给客户端。
- 因为有大量用户短时间内进入到了详情页,所以可以把活动列表缓存起来,直接读缓存就可以了。
- 那下次再查询商品时,直接去缓存查询就可以了。如果秒杀商品下架了,缓存的数据不会用到了,就把缓存删掉就可以了。
代码实现
自定义注解
自定义注解
Cache:
package com.huing.blog.common.cache;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {
//过期时间
long expire() default 1 * 60 * 1000;
//缓存标识 key
String name() default "";
}
aop逻辑实现
就是找到加了@cache注解的方法,把返回值和相关参数属性放到redis缓存里。
package com.huing.blog.common.cache;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huing.blog.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.time.Duration;
@Aspect
@Component
@Slf4j
public class CacheAspect {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private RedisTemplate redisTemplate;
//切点,注解加在那里,那里就是切点
@Pointcut("@annotation(com.huing.blog.common.cache.Cache)")
public void pt(){}
//环绕通知,在方法的前后进行增强
@Around("pt()")
public Object around(ProceedingJoinPoint pjp){
try {
Signature signature = pjp.getSignature();
//类名
String className = pjp.getTarget().getClass().getSimpleName();
//调用的方法名
String methodName = signature.getName();
Class[] parameterTypes = new Class[pjp.getArgs().length];
Object[] args = pjp.getArgs();
//参数
String params = "";
for(int i=0; i
Controller控制层使用
ArticleController:
@PostMapping("hot")
@Cache(expire = 5 * 60 * 1000,name = "hot_article")
public Result hotArticle(){
return articleService.hotArticle(limit);
}
实现效果
Sprting Cache
Spring Cache简介
Spring Cache 是 Spring 提供的一整套的缓存解决方案。虽然它本身并没有提供缓存的实现,但是它提供了一整套的接口和代码规范、配置、注解等,这样它就可以整合各种缓存方案了,比如 Redis、Ehcache,我们也就不用关心操作缓存的细节。
Cache接口它包含了缓存的各种操作方式,同时还提供了各种xxxCache缓存的实现,比如 RedisCache 针对Redis,EhCacheCache 针对 EhCache,ConcurrentMapCache 针对 ConCurrentMap。
Spring Cache使用效果
每次调用某方法,而此方法又是带有缓存功能时,Spring 框架就会检查指定参数的那个方法是否已经被调用过,如果之前调用过,就从缓存中取之前调用的结果;如果没有调用过,则再调用一次这个方法,并缓存结果,然后再返回结果,那下次调用这个方法时,就可以直接从缓存中获取结果了。
缓存注解
| 注解 | 描述 |
| @Cacheable | 在调用方法前,首先去缓存中找方法的返回值,如果能找到,则返回缓存的值,否则就执行这个方法,并将返回值放到缓存中。 |
| @CachePut | 在方法调用前不会去缓存中找,无论如何都会执行方法,执行后将缓存数据放入缓存中。 |
| @CacheEvict | 清理缓存中的一个或多个记录 |
| @Caching | 能够同时应用多个缓存注解 |
| @CacheConfig | 在类级别共享相同的缓存的配置 |
Cacheable注解
- 标记在一个方法上,也可以标记在一个类上
- 缓存标注对象的返回结果,标注在方法上缓存该方法的返回值,标注在类上缓存该类所有方法的返回值
- value缓存名称,可以有多个
- key缓存的key规则,可以使用springEL表达式,默认是方法参数组合
- condition缓存条件,使用springEL编写,返回true才缓存
案例:
//对象
@Cacheable(value = {"product"},key = "#root.methodName")//分页
@Cacheable(value = {"product_page"}, key = "#root.methodName + #page + '_' + #size")
在线博客系统SpringCache使用
在本项目中使用Spring Cache
编码实现
pop依赖
org.springframework.boot
spring-boot-starter-cache
application.properties配置文件
#cache 配置文件指定缓存类型
spring.cache.type=redis
启动类开启缓存注解
package com.huing.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class BlogApp {
public static void main(String[] args) {
SpringApplication.run(BlogApp.class,args);
}
}
CacheConfig配置文件
package com.huing.blog.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager1Minute(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(60L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
@Primary // 默认的,没有指定采用默认的
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600 * 24L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
private RedisCacheConfiguration instanceConig(long ttl) {
Jackson2JsonRedisSerializer
缓存注解实现
org.springframework.boot
spring-boot-starter-cache
application.properties配置文件
#cache 配置文件指定缓存类型
spring.cache.type=redis
启动类开启缓存注解
package com.huing.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class BlogApp {
public static void main(String[] args) {
SpringApplication.run(BlogApp.class,args);
}
}
CacheConfig配置文件
package com.huing.blog.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager1Minute(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(60L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
@Primary // 默认的,没有指定采用默认的
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600 * 24L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
private RedisCacheConfiguration instanceConig(long ttl) {
Jackson2JsonRedisSerializer
缓存注解实现
package com.huing.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class BlogApp {
public static void main(String[] args) {
SpringApplication.run(BlogApp.class,args);
}
}
CacheConfig配置文件
package com.huing.blog.config;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
@Configuration
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager1Minute(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(60L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
@Primary // 默认的,没有指定采用默认的
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config = instanceConig(3600 * 24L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
private RedisCacheConfiguration instanceConig(long ttl) {
Jackson2JsonRedisSerializer
缓存注解实现
例如,我们想在对newArticle(最新文章)接口实现SpringCache缓存,直接添加Cacheable注解即可:
@PostMapping("new")
@Cacheable(value = {"newArticle"}, key = "#root.methodName",cacheManager = "cacheManager1Minute") //这里我们设置过期时间为1分钟,默认为一小时
public Result newArticle() {
return articleService.newArticle(limit);
}
效果展示
前端发送对应请求之后,redis中:
可以发现,缓存的名称是newArticle,缓存的key为方法名称newArticle,并且当前过期时间为34秒(设置的为60秒)。
SpringCache详解请参考:
暑期编程PK赛 得CSDN机械键盘等精美礼品!


