spring-boot-cache支持如下缓存
Generic、JCache (JSR-107)、EhCache 2.x、Hazelcast、Infinispan、Redis、Guava、Simple
一、快速入门 1、添加依赖2、启动类添加注解org.springframework.boot spring-boot-starter-cache
- @EnableCaching 用于缓存配置类或者启动类上
spring.cache.type指定缓存组件,详细的见下面的
spring:
cache:
type: XXX ## 设置缓存类型为caffeine
4、业务类使用注解以及使用
- @CacheConfig 单个缓存管理配置,添加在需要缓存类上
- cacheNames或value 指定缓存名称
- cacheManager 指定的缓存换利器
- cacheResolver 指定的缓存解析器
- @Cacheable 用于查询方法上,表示缓存查询的结果
- key= “#root.methodName” 指定缓存key的表达式,一般采用spEL表达式
- condition = “#id>2” 缓存的条件,例如id>2
- unless = “#a0==null” 不缓存的条件,例如第一个参数为null
- keyGenerator 指定缓存的key生成器
- sync 默认为false,实际调用方法获取数据时是否要保持同步
- @CachePut 用于更新方法上,表示更新缓存
- key = “#student.id”
- condition 满足条件时更新缓存,支持SpEL表达式
- unless 满足条件时不更新缓存,支持spEL表达式
- @CacheEvict 用于删除方法上,表示删除缓存
- key = “#id” 指定缓存的key
- allEntries = true 默认为false,是否要清除所有缓存数据
- value或cacheNames 指定缓存名称
- condition 满足条件时删除缓存,支持SpEL表达式
- beforeInvocation 默认为false,调用方法之前或之后清除缓存
- @Caching 用在一个方法上多种注解
- cacheable 对应的是@Cacheable
- put 对应的是配置@CachePut
- evict 对应的是@CacheEvict
@CacheConfig(cacheNames = "student")
public class StudentService {
//表示将sno作为key,添加key
@Cacheable(key= "#root.methodName",condition = "#id>2",unless = "#a0==null")
public Student queryStudentBySno(Integer id){
//添加缓存
}
//#p0.sno表示将student的sno作为key,更新key
@CachePut(key = "#student.id")
public Student update(Student student){
//更新缓存
}
//将sno作为key,移除缓存中的key
@CacheEvict(key = "#id", allEntries = true)
public void deleteStudentBySno(Integer id){
//删除缓存
}
}
二、使用Caffine缓存组件(基于内存缓存)
1、添加依赖
2、修改配置com.github.ben-manes.caffeine caffeine 2.6.0
- maximumWeight=[long]: 缓存的最大权重
- expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
- expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
- refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
- weakKeys: 打开key的弱引用
- softValues:打开value的软引用
- recordStats:开发统计功能
- initialCapacity=[integer]: 初始的缓存空间大小
spring:
cache:
type: caffeine ## 设置缓存类型为caffeine
cache-names:
- getPersonById # 指定缓存名称
- name2
caffeine:
spec: maximumSize=500,expireAfterWrite=5s # 缓存配置
3、Caffine本身API灵活运用
(1)定义缓存枚举
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum Caches{
getPersonById(5), //有效期5秒
getSomething, //缺省10秒
getOtherthing(300, 1000), //5分钟,最大容量1000
;
//缺省情况
private int maxSize=50000; //最大數量
private int ttl=10; //过期时间(秒)
Caches(int ttl) {
this.ttl = ttl;
}
}
(2)自定义缓存配置类
@Configuration
@EnableCaching
public class CacheConfig {
public static final int DEFAULT_MAXSIZE = 50000;
public static final int DEFAULT_TTL = 10;
@Bean
@Primary
public CacheManager caffeineCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
ArrayList caches = new ArrayList();
//从缓存枚举中获取到所有情况的缓存
for(Caches c : Caches.values()){
caches.add(new CaffeineCache(c.name(),
Caffeine.newBuilder().recordStats()
.expireAfterWrite(c.getTtl(), TimeUnit.SECONDS)
.maximumSize(c.getMaxSize())
.build())
);
}
cacheManager.setCaches(caches);
return cacheManager;
}
@Bean
public CacheLoader
(3)使用API操作
//缓存加载器 LoadingCache三、使用Redis作为缓存组件 1、添加依赖loadingCache = Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(10, TimeUnit.MINUTES) .build(key -> createExpensiveGraph(key)); //查询数据先查询缓存 private Object createExpensiveGraph(String key) { Object graph = null; //先查询缓存是否存在,这里也可以做成函数式编程 graph = manualCache.getIfPresent(key); if(null != graph){ return graph; } return personService.findOne1(); } //关于Caffine缓存的增删改查使用 public Object testManual(Person person) { String key = "name1"; Object graph = null; // 根据key查询一个缓存,如果没有返回NULL graph = manualCache.getIfPresent(key); // 根据Key查询一个缓存,如果没有调用createExpensiveGraph方法,并将返回值保存到缓存。 // 如果该方法返回Null则manualCache.get返回null,如果该方法抛出异常则manualCache.get抛出异常 graph = manualCache.get(key, k -> createExpensiveGraph(k)); // 将一个值放入缓存,如果以前有值就覆盖以前的值 manualCache.put(key, graph); // 删除一个缓存 manualCache.invalidate(key); ConcurrentMap map = manualCache.asMap(); System.out.println(map.toString()); return graph; } //异步缓存 AsyncLoadingCache asyncLoadingCache = Caffeine.newBuilder() .maximumSize(10_000) .expireAfterWrite(10, TimeUnit.MINUTES) .buildAsync(key -> createExpensiveGraph(key)); private CompletableFuture createExpensiveGraphAsync( String key, Executor executor) { CompletableFuture objectCompletableFuture = new CompletableFuture<>(); return objectCompletableFuture; }
2、添加配置org.springframework.boot spring-boot-starter-data-redis
spring:
redis:
database: 0 # Redis数据库索引(默认为0)
host: localhost # Redis服务器地址
port: 6379 # Redis服务器连接端口
pool:
max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
timeout: 0 # 连接超时时间(毫秒)
3、添加配置类
这里定义的缓存key生成策略,缓存管理器,模板类都可以使用到@CacheConfig注解中
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
// 自定义缓存key生成策略
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
// 缓存管理器
@Bean
public CacheManager cacheManager( RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间
cacheManager.setDefaultExpiration(10000);
return cacheManager;
}
//redis模板类
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
setSerializer(template);// 设置序列化工具
template.afterPropertiesSet();
return template;
}
//设置序列化和发序列化
private void setSerializer(StringRedisTemplate template) {
@SuppressWarnings({ "rawtypes", "unchecked" })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
}
}
4、使用Redis的API(基于Jedis客户端实现)
基于StringRedisTemplate即字符串序列化的可用方法
//Redis的示例以及对所有key操作 StringRedisTemplate redisTemplate; redisTemplate.delete(key); redisTemplate.delete(keys); redisTemplate.hasKey(key); redisTemplate.expire(key,expireTime, TimeUnit.SECONDS); redisTemplate.keys(key); //Hash类型数据操作 HashOperations四、使用JetCache作为缓存组件hashOpt = redisTemplate.opsForHash(); hashOpt.get(hashKey, hashItem); hashOpt.put(hashKey, hashItem, value); hashOpt.entries(hashKey); hashOpt.values(hashkey); hashOpt.delete(hashKey, hashItem); hashOpt.putAll(key, var2); //Set类型操作 SetOperations setOpt = redisTemplate.opsForSet(); setOpt.add(key,value); setOpt.remove(key,value); setOpt.members(key); //Zset类型操作 Map scoreMap = Maps.newHashMapWithExpectedSize(1); scoreMap.put(val,score); zsetAddAll(key,scoreMap); reverseRangeWithScores(key,start, end); reverseRangeWithScores(key,start, end); remove(key,value); incrementScore(key, item, score); size(key); rank(key, item); //其他略
- JetCache作为代理Redis或者Caffine缓存组件
- JetCache可以设置一级缓存和二级缓存
2、添加配置com.alicp.jetcache jetcache-starter-redis-lettuce 2.6.0.M1 org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
# 一级本地缓存
local:
default:
type: linkedhashmap
keyConvertor: fastjson
otherCacheName:
type: linkedhashmap
keyConverter: fastjson
# 二级远程缓存
remote:
default:
type: redis.lettuce
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
uri:
- redis://password@192.168.14.231:6379/0 #redis://密码@IP:端口/库
- redis://password@192.168.14.232:6379/0
- redis://password@192.168.14.233:6379/0
readFrom: masterPreferred #master优先
2、添加类配置
- @EnableMethodCache 开启方法级缓存
- @EnableCreateCacheAnnotation 开启创建缓存注解
@SpringBootApplication
@EnableMethodCache(basePackages = { "com.xxxx" })
@EnableCreateCacheAnnotation
public class Application {
SpringApplication.run(Application.class,args);
}
3、在控制层开启缓存
@RestController
public class UserController {
// 定义一个是String类型的远程缓存
@CreateCache(name ="i5xforyou.username", expire = 120, cacheType = CacheType.REMOTE)
private Cache userNameCache;
// 定义一个是User对象的二级缓存(本地+远程)
@CreateCache(name ="i5xforyou.user", localExpire = 60, localLimit = 100, expire = 120, cacheType = CacheType.BOTH)
private Cache userCache;
@GetMapping(value = "/getUser")
public String getUserInfo() {
// 远程缓存
userNameCache.put("123", "userName");
System.out.println("userNameCache : " + userNameCache.get("123"));
User user = new User();
user.setUserName("user.userName");
//远程二级缓存
userCache.put("1234", user);
System.out.println("userCache: " + userCache.get("1234").geUserName());
return "";
}
}
4、在业务接口上开启缓存
public interface UserService {
@Cached(name="userCache-", key="#userId", expire = 3600)
User getUserById(long userId);
@CacheUpdate(name="userCache-", key="#user.userId", value="#user")
void updateUser(User user);
@CacheInvalidate(name="userCache-", key="#userId")
void deleteUser(long userId);
@Cached(expire = 3600, cacheType = CacheType.REMOTE)
@CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS)
@CachePenetrationProtect
BigDecimal summaryOfToday(long catagoryId);
}
5、使用缓存池以及相关API
## JedisPool创建对象池
GenericObjectPoolConfig pc = new GenericObjectPoolConfig();
pc.setMinIdle(2);
pc.setMaxIdle(10);
pc.setMaxTotal(10);
JedisPool pool = new JedisPool(pc, "localhost", 6379);
## 创建userCache
Cache userCache = RedisCacheBuilder.createRedisCacheBuilder()
.keyConvertor(FastjsonKeyConvertor.INSTANCE)
.valueEncoder(JavaValueEncoder.INSTANCE)
.valueDecoder(JavaValueDecoder.INSTANCE)
.jedisPool(pool)
.keyPrefix("userCache-")
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();
CacheGetResult r = cache.GET(userId);
CompletionStage future = r.future();
future.thenRun(() -> {
if(r.isSuccess()){
System.out.println(r.getValue());
}
})
## 使用分布式锁
cache.tryLockAndRun("key", 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());
## 数据预加载
@CreateCache
@CacheRefresh(timeUnit = TimeUnit.MINUTES, refresh = 60, stopRefreshAfterLastAccess = 100)
@CachePenetrationProtect
private Cache orderSumCache;
@PostConstruct
public void init(){
orderSumCache.config().setLoader(this::loadOrderSumFromDatabase);
}
五、使用EhCache
springboot没有对ehcache进行整合,只能使用原生的方式
1、添加依赖2、添加ehcache.xml配置文件net.sf.ehcache ehcache
- diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
- defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
- name:缓存名称。
- maxElementsInMemory:缓存最大数目
- maxElementsOnDisk:硬盘最大缓存个数。
- eternal:对象是否永久有效,一但设置了,timeout将不起作用。
- overflowToDisk:是否保存到磁盘,当系统宕机时
- timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
- timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
- diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
- diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
- clearOnFlush:内存数量最大时是否清除。
3、添加配置
spring:
cache:
ehcache:
config: 'classpath:ehcache.xml'
4、Ehcache的缓存使用
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class TestCache {
@Resource
private CacheManager cacheManager;
@Test
public void cacheTest() {
// 显示所有的Cache空间
System.out.println(StringUtils.join(cacheManager.getCacheNames(), ","));
Cache cache = cacheManager.getCache("userCache");
cache.put("key", "123");
System.out.println("缓存成功");
String res = cache.get("key", String.class);
System.out.println(res);
}
}
CacheManager转换
/ 获取EhCache的管理器
org.springframework.cache.ehcache.EhCacheCacheManager cacheCacheManager = (EhCacheCacheManager) cacheManager;
net.sf.ehcache.CacheManager ehCacheManager = cacheCacheManager.getCacheManager();
net.sf.ehcache.Cache ehCache = ehCacheManager.getCache("userCache");
六、使用Memcache缓存组件
Springboot没有对Memcache做整合
1、添加依赖2、添加配置net.spy spymemcached 2.12.3
memcache: ip: 192.168.0.161 port: 112113、添加配置类
@Data
@Component
@ConfigurationProperties(prefix = "memcache")
public class MemcacheSource {
private String ip;
private int port;
}
4、初始化Memcache对象
@Component
public class MemcachedRunner implements CommandLineRunner {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private MemcacheSource memcacheSource;
private MemcachedClient client = null;
@Override
public void run(String... args) throws Exception {
try {
client = new MemcachedClient(
new InetSocketAddress(
memcacheSource.getIp(),
memcacheSource.getPort()));
} catch (IOException e) {
logger.error("inint MemcachedClient failed ",e);
}
}
public MemcachedClient getClient() {
return client;
}
}
5、使用Memcache
@RunWith(SpringRunner.class)
@SpringBootTest
public class RepositoryTests {
@Resource
private MemcachedRunner memcachedRunner;
@Test
public void testSetGet() {
MemcachedClient memcachedClient = memcachedRunner.getClient();
//测试添加缓存
memcachedClient.set("testkey",1000,"666666");
//测试获取缓存
String test= memcachedClient.get("testkey").toString();
System.out.println(test);
}
}



