Spring从3.1开始定义了一系列抽象接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们进行缓存开发。Spring Cache 只负责维护抽象层,具体的实现由你的技术选型来决定。将缓存处理和缓存技术解除耦合。
Spring Cache接口为缓存的组件规范定义,包含缓存的各种操作集合,并提供了各种xxxCache的实现,如RedisCache,EhCacheCache,ConcurrentMapCache等;
项目整合Spring Cache后每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过,如果有就直接从缓存中获取结果,没有就调用方法并把结果放到缓存。
对于缓存声明,Spring的缓存提供了一组java注解:
@CacheConfig:设置类级别上共享的一些常见缓存设置。
@Cacheable:触发缓存写入。
@CacheEvict:触发缓存清除。
@Caching 将多种缓存操作分组
@CachePut:更新缓存(不会影响到方法的运行)。
org.springframework.boot
spring-boot-starter-cache
@EnableCaching注解是spring framework中的注解驱动的缓存管理功能,当你在配置类(@Configuration)上使用@EnableCaching注解时,会触发一个post processor,这会扫描每一个spring bean,查看是否已经存在注解对应的缓存。如果找到了,就会自动创建一个代理拦截方法调用,使用缓存的bean执行处理。
@EnableCaching
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@Slf4j
@Service
public class UserService {
//查询数据库后 数据添加到缓存
@Cacheable(cacheNames = "cacheManager", key = "'USER:'+#id", unless = "#result == null")
public Map get(String id) {
log.info("获取:" + id);
Map map = new HashMap<>();
map.put("id", id);
map.put("username", "zhangsan");
return map;
}
//清除一条缓存,key为要清空的数据
@CacheEvict(cacheNames = "cacheManager", key = "'USER:'+#id")
public void delete(String id) {
log.info("删除:" + id);
}
//修改数据后更新缓存
@CachePut(cacheNames = "cacheManager", key = "'USER:'+#userInfo['id']", unless = "#result == null")
public void update(Map userInfo) {
log.info("新增[修改]:" + userInfo.toString());
}
}
org.springframework.boot
spring-boot-starter-test
test
package com.demo;
import com.demo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
class SpringCacheApplicationTests {
@Autowired
private UserService userService;
@Test
void contextLoads() {
Map userInfo = new HashMap<>();
userInfo.put("id", "123");
userInfo.put("username", "zhangsan");
System.out.println("新增缓存--------------------------------");
userService.update(userInfo);
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("删除缓存--------------------------------");
userService.delete((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
}
}
Spring Boot 2.x中 默认使用lettuce作为默认redis客户端。当然你也可以引入redisson客户端。这两种是非阻塞反应式高级redis客户端。建议放弃阻塞客户端jedis。
org.springframework.boot
spring-boot-starter-data-redis
org.apache.commons
commons-pool2
server.port=8765
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=
spring.cache.type=redis
其他配置可通过前缀spring.cache、spring.redis进行配置
@Slf4j
@Service
public class UserService {
//查询数据库后 数据添加到缓存
@Cacheable(cacheNames = "redisCacheManager", key = "'USER:'+#id", unless = "#result == null")
public Map get(String id) {
log.info("获取:" + id);
Map map = new HashMap<>();
map.put("id", id);
map.put("username", "zhangsan");
return map;
}
//清除一条缓存,key为要清空的数据
@CacheEvict(cacheNames = "redisCacheManager", key = "'USER:'+#id")
public void delete(String id) {
log.info("删除:" + id);
}
//修改数据后更新缓存
@CachePut(cacheNames = "redisCacheManager", key = "'USER:'+#userInfo['id']", unless = "#result == null")
public void update(Map userInfo) {
log.info("新增[修改]:" + userInfo.toString());
}
}
package com.demo;
import com.demo.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
class SpringCacheApplicationTests {
@Autowired
private UserService userService;
@Test
void contextLoads() {
Map userInfo = new HashMap<>();
userInfo.put("id", "123");
userInfo.put("username", "zhangsan");
System.out.println("新增缓存--------------------------------");
userService.update(userInfo);
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("删除缓存--------------------------------");
userService.delete((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
}
}
@Configuration
public class CacheConfig {
@Value("#{${spring.cache.redis.defaultTime}}")
private Integer defaultTime;
@Value("#{${spring.cache.redis.configMap}}")
private Map configMap;
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(defaultTime),
this.getRedisCacheConfigurationMap()
);
}
private Map getRedisCacheConfigurationMap() {
Map redisCacheConfigurationMap = new HashMap<>();
Set> entries = configMap.entrySet();
for (Map.Entry entry : entries) {
redisCacheConfigurationMap.put(entry.getKey(), this.getRedisCacheConfigurationWithTtl(entry.getValue()));
}
return redisCacheConfigurationMap;
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
Jackson2JsonRedisSerializer
# 默认缓存过期时间(单位/秒)
spring.cache.redis.defaultTime=18000
# redis缓存时间配置(key:缓存名,value:过期时间/单位秒)
spring.cache.redis.configMap={"USER":18000}
@Slf4j
@Service
@CacheConfig(cacheNames = "USER", cacheManager = "redisCacheManager")
public class User2Service {
//查询数据库后 数据添加到缓存
@Cacheable(key = "#id")
public Map get(String id) {
log.info("获取:" + id);
Map map = new HashMap<>();
map.put("id", id);
map.put("username", "zhangsan");
return map;
}
//清除一条缓存,key为要清空的数据
@CacheEvict(key = "#id")
public void delete(String id) {
log.info("删除:" + id);
}
//修改数据后更新缓存
@CachePut(key = "#userInfo['id']")
public void update(Map userInfo) {
log.info("新增[修改]:" + userInfo.toString());
}
}
@SpringBootTest
class SpringCacheApplicationTests {
@Autowired
private User2Service userService;
@Test
void contextLoads() {
Map userInfo = new HashMap<>();
userInfo.put("id", "123");
userInfo.put("username", "zhangsan");
System.out.println("新增缓存--------------------------------");
userService.update(userInfo);
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
System.out.println("删除缓存--------------------------------");
userService.delete((String) userInfo.get("id"));
System.out.println("获取缓存--------------------------------");
userService.get((String) userInfo.get("id"));
}
}