SpringBoot整合EhCache
最佳答案 问答题库658位专家为你答疑解惑
文章目录
- 前言
- 构建SpringBoot工程
- 导入依赖
- 准备EhCache的配置项
- 配置CachaManager
- Cache注解使用
- 基本使用
- key的声明方式
- Spel表达式语言实现
- KeyGenerator实现
- 缓存条件
- condition
- unless
- condition&unless的优先级
- sync
- @CachePut
- @CacheEvict
- @Caching
前言
SpringBoot默认情况下是整合了EhCache的,但是默认整合的EhCache的2.x版本,本文依然整合EhCache的3.x版本。
构建SpringBoot工程
导入依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.ehcache</groupId><artifactId>ehcache</artifactId><version>3.8.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency>
</dependencies>
准备EhCache的配置项
# 准备EhCache基础配置项
ehcache:heap: 1000 # 堆内内存缓存个数off-heap: 10 # 对外内存存储大小 MBdisk: 20 # 磁盘存储数据大小 MBdiskDir: D:/data/ # 磁盘存储路径cacheNames: # 基于CacheManager构建多少个缓存- user- item- card
引入配置文件中的配置项
@Component
@ConfigurationProperties(prefix = "ehcache")
public class EhCacheProps {private int heap;private int offheap;private int disk;private String diskDir;private Set<String> cacheNames;}
配置CachaManager
@Configuration
@EnableCaching
public class EhCacheConfig {@Autowiredprivate EhCacheProps ehCacheProps;@Beanpublic CacheManager ehCacheManager(){//1. 缓存名称Set<String> cacheNames = ehCacheProps.getCacheNames();//2. 设置内存存储位置和数量大小ResourcePools resourcePools = ResourcePoolsBuilder.newResourcePoolsBuilder().heap(ehCacheProps.getHeap()).offheap(ehCacheProps.getOffheap(), MemoryUnit.MB).disk(ehCacheProps.getDisk(),MemoryUnit.MB).build();//3. 设置生存时间ExpiryPolicy expiry = ExpiryPolicyBuilder.noExpiration();//4. 设置CacheConfiguration// baseObject是一个POJO类实现了序列化接口CacheConfiguration cacheConfiguration = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, BaseObject.class, resourcePools).withExpiry(expiry).build();//5. 设置磁盘存储的位置CacheManagerBuilder<PersistentCacheManager> cacheManagerBuilder =CacheManagerBuilder.newCacheManagerBuilder().with(CacheManagerBuilder.persistence(ehCacheProps.getDiskDir()));//6. 缓存名称设置好。for (String cacheName : cacheNames) {cacheManagerBuilder.withCache(cacheName,cacheConfiguration);}//7. 构建return cacheManagerBuilder.build();}
}
Cache注解使用
Cache注解是JSR规范中的,Spring支持这种注解。前面配置好关于CacheManager之后,就可以在Service层添加Cache注解,实现缓存使用,缓存更新,缓存清除。
基本使用
这个是查询缓存的注解,可以加在方法上,也可以加在类上(不建议添加在类上,这样很多细粒度配置就无法实现,比如@Transactional),可以在执行当前方法前,根据注解查看方法的返回内容是否已经被缓存,如果已经缓存,不需要执行业务代码,直接返回数据。如果没有命中缓存,正常执行业务代码,在执行完毕后,会将返回结果作为缓存,存储起来。
直接在Service层的方法上添加@Cacheable,注意,必须填写@Cacheable中的value或者cacheName属性
默认情况下,每次查询会基于Key(默认是方法的参数)去查看是否命中缓存
- 如果命中缓存,直接返回
- 如果未命中缓存,正常执行业务代码,基于方法返回结果做缓存
key的声明方式
key的声明方式有两种,一种是基于Spring的Expression Language去实现,另一种是基于编写类的方式动态的生成key
Spel表达式语言实现
@Override
@Cacheable(cacheNames = {"item"},key = "#id") // 123
public String echo(String id,String... args) {System.out.println("查询数据库~");// itemMapper.findById(id);return id;
}
这种方式要基于Spel实现,但是Spel用的不多,单独为了这种操作熟悉Spel成本蛮高的,而且功能并不丰富,所以更推荐第二种方式,编写类的方式设置key的生成策略
KeyGenerator实现
这种方式需要在Spring容器中构建KeyGenerator实现类,基于注解配置进去即可
设置key的生成策略。
@Configuration
public class CacheKeyGenerator {@Bean(name = "itemKeyGenerator")public KeyGenerator itemKeyGenerator(){return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName() + params[0];}};}
}
设置bean name到keyGenerator中
@Override
@Cacheable(cacheNames = {"item"},keyGenerator = "itemKeyGenerator")
public String echo(String id,String... args) {System.out.println("查询数据库~");// itemMapper.findById(id);return id;
}
缓存条件
在执行方法前后,判断当前数据是否需要缓存,所以一般基础参数的判断。
- 条件为true代表缓存(condition)
- 条件为false代表缓存(unless)
都可以基于Spel编写条件表达式
condition
在执行方法前,决定是否需要缓存
可以在condition中编写Spel,只要条件为true,既代表当前数据可以缓存
@Override
@Cacheable(cacheNames = {"item"},condition = "#id.equals(\"123\")")
public String echo(String id) {System.out.println("查询数据库~");// itemMapper.findById(id);return id;
}
unless
执行方法之后,决定是否需要缓存
unless也可以编写Spel,条件为false时,代表数据可以缓存,如果为true,代表数据不需要缓存
@Override
@Cacheable(cacheNames = {"item"},unless = "#result.equals(\"123\")")
public String echo(String id) {System.out.println("查询数据库~");// itemMapper.findById(id);return id;
}
更多的其实还是在执行查询前,来判断数据是否需要缓存。如果真的需要做,也是避免诡异的操作。
比如Service在出现异常结果时,返回-1,那么这种-1,就不需要缓存。
condition&unless的优先级
condition和unless都是代表是都需要缓存数据。
如果同时设置condition和unless。
- condition,unless
- true,false:unless代表不缓存,那就不缓存
- true,true:都代表缓存,那就缓存
- false,false:都不让缓存, 那就不缓存
- false,true:condition代表不缓存数据,那就不缓存
condition和unless没有优先级之分,他的优先级在于,不缓存的优先级高于缓存。
sync
缓存击穿问题。
当多个线程并发访问一个Service方法时,发现当前方法没有缓存数据,此时会让一个线程去执行业务代码查询数据,扔到缓存中,后面线程再查询缓存
可以设置sync属性为true,代表当执行Service方法时,发现缓存没数据,那么就需要去竞争锁资源去执行业务代码,后续线程等待前置线程执行完,再去直接查询缓存即可
@Override
@Cacheable(cacheNames = {"item"},sync = true)
public String echo(String id) {System.out.println("查询数据库~");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return id;
}
@CachePut
@CachePut注解是在写数据之后,更新缓存的数据
在增删改的操作上追加@CachePut注解,会根据key去重置指定的缓存。
细节点就在于对标上查询方法的key
@Override
@CachePut(cacheNames = "item",key = "#item.id")
public String write(Item item) {// 写id为123的数据System.out.println("123被改成456");return "456";
}
@CacheEvict
@CacheEvict是用来清除缓存的,可以根据注解里的cacheNames和key来清除指定缓存,也可以清除整个cacheNames中的全部缓存
清除指定缓存
@Override
@CacheEvict(value = "item")
public void clear(String id) {System.out.println("清除缓存成功!");
}
清除全部缓存
@Override
@CacheEvict(value = "item",allEntries = true)
public void clearAll() {System.out.println("清除item中的全部缓存~!");
}
如果执行清除缓存过程中,业务代码出现异常,会导致无法正常清除缓存,可以设置一个属性来保证在方法业务执行之前,就将缓存正常清除beforeInvocation设置为true
@Override
@CacheEvict(value = "item",allEntries = true,beforeInvocation = true)
public void clearAll() {int i = 1 / 0;System.out.println("方法执行前,清除item中的全部缓存~!");
}
@Caching
一个组合数据,可以基于Caching实现@Cacheable,@CachePut以及@CacheEvict三个注解
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"SpringBoot整合EhCache":http://eshow365.cn/6-9483-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!