目录:
1.Spring break in Mexico翻译
2.SPRING BREAK IN MEXICO在线试听
3.SPRING BREAK IN MEXICO舞蹈
4.SPRING BREAK IN MEXICO 百度百科
5.SPRING BREAK IN MEXICO热门歌女野王
6.SPRING BREAK IN MEXICO什么意思
7.SPRING BREAK IN THE MEXICO
8.SPRING BREAK IN MEXICO歌词
9.SPRING BREAK IN MEXICO热门歌女野王视频
10.SPRING BREAK IN MEXICO伴奏
1.Spring break in Mexico翻译
今天我们来看看 Caffeine 如何与 SpringBoot 集成的集成caffeinecaffeine 与 SpringBoot 集成有两种方式:一种是我们直接引入 Caffeine 依赖,然后使用 。
2.SPRING BREAK IN MEXICO在线试听
Caffeine 方法实现缓存相当于使用原生apiCaffeine Spring Cache SpringCacheorg.springframework.boot。
3.SPRING BREAK IN MEXICO舞蹈
spring-boot-starter-cachecom.github.ben-manes.caffeine
4.SPRING BREAK IN MEXICO 百度百科
caffeine2.6.0第一种方式首先配置一个 Cache ,通过构造者模式构建一个
5.SPRING BREAK IN MEXICO热门歌女野王
Cache 对象,然后后续关于缓存的增删查都是基于这个 cache 对象@ConfigurationpublicclassCacheConfig{ @Beanpublic Cache 。
6.SPRING BREAK IN MEXICO什么意思
caffeineCache(){ return Caffeine.newBuilder() // 设置最后一次写入或访问后经过固定时间过期 .expireAfterWrite(
7.SPRING BREAK IN THE MEXICO
60, TimeUnit.SECONDS) // 初始的缓存空间大小 .initialCapacity(100)
8.SPRING BREAK IN MEXICO歌词
// 缓存的最大条数 .maximumSize(1000) .build(); } 第一种方式我们就一一不介绍了,基本上就是使用
9.SPRING BREAK IN MEXICO热门歌女野王视频
caffeineCache 来根据你自己的业务来操作以下方法
10.SPRING BREAK IN MEXICO伴奏
这种方式使用的话是对代码有侵入性的第二种方式EnableCaching dubbo @EnableDubbole@SpringBootApplication@EnableCaching public class DemoApplication { 。
publicstaticvoidmain(String[] args) { SpringApplication.run(DemoApplication.class, args); }
在 application.yml 配置我们的使用的缓存类型、过期时间、缓存策略等spring: profiles: active: devcache: type: CAFFEINE。
caffeine: spec: maximumSize=500,expireAfterAccess=600s如果我们不习惯使用这种方式的配置,当然我们也可以使用 JavaConfig 的配置方式来代替配置文件。
@ConfigurationpublicclassCacheConfig{ @Beanpublic CacheManager cacheManager(){ CaffeineCacheManager cacheManager =
new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder()
// 设置最后一次写入或访问后经过固定时间过期 .expireAfterAccess(600, TimeUnit.SECONDS)
// 初始的缓存空间大小 .initialCapacity(100) // 缓存的最大条数 .maximumSize(
500)); return cacheManager; } 接下来就是代码中如何来使用这个缓存了@Override@CachePut(value = “user”
, key = “#userDTO.id”)public UserDTO save(UserDTO userDTO) { userRepository.save(userDTO);
return userDTO; } @Override@CacheEvict(value = “user”, key = “#id”)//2public void remove(Long
id) { logger.info(“删除了id、key为” + id + “的数据缓存”); } @Override@Cacheable(value = “user”
,key = “#id”)public UserDTO getUserById(Long id) { return userRepository.findOne(id); }
上述代码中我们可以看到有几个注解 @CachePut、@CacheEvict、@Cacheable 我们只需要在方法上标上这几个注解,我们就能够使用缓存了,我们分别来介绍下这几个注解@Cacheable。
@Cacheable 它是既可以标注在类上也可以标注在方法上,当它标记在类上的时候它表述这个类上面的所有方法都会支持缓存,同样的 当它作用在法上面时候它表示这个方法是支持缓存的比如上面我们代码中的 getUserById
这个方法第一次缓存里面没有数据,我们会去查询 DB ,但是第二次来查询的时候就不会走 DB 查询了,而是直接从缓存里面拿到结果就返回了value 属性@Cacheable value CacheCache。
key@Cacheable keykey SimpleKeyGenerator keypublicstatic Object generateKey(Object… params) {
// 如果方法没有参数 key就是一个 new SimpleKey()if (params.length == 0) { return SimpleKey.EMPTY; } // 如果方法只有一个参数 key就是当前参数
if (params.length == 1) { Object param = params[0]; if (param != null && !param.getClass().isArray()) {
return param; } } // 如果key是多个参数,key就是new SimpleKey ,不过这个SimpleKey对象的hashCode 和Equals方法是根据方法传入的参数重写的。
returnnew SimpleKey(params); } 上述代码还是非常好理解的分为三种情况:方法没有参数,那就new使用一个全局空的 SimpleKey 对象来作为 key 方法就一个参数,就使用当前参数来作为 。
key1new SimpleKey keynew SimpleKey SimpleKey hashCode equals Map key hashCode equals caffein ConcurrentHashMap
小结上述代码我们可以发现默认生成 key 只跟我们传入的参数有关系,如果我们有一个类里面如果存在多个没有参数的方法,然后我们使用了默认的缓存生成策略的话,就会造成缓存丢失或者缓存相互覆盖,或者还有可能会发生 。
ClassCastException 因为都是使用同一个 key 比如下面这代码就会发生异常( ClassCastException ) @Cacheable(value = “user”) 。
public UserDTO getUser() { UserDTO userDTO = new UserDTO(); userDTO.setUserName(“Java金融”
); return userDTO; } @Cacheable(value = “user”) public UserDTO2 getUser1() { UserDTO2 userDTO2 =
new UserDTO2(); userDTO2.setUserName2(“javajr.cn”); return userDTO2; } 所以一般不怎么推荐使用默认的缓存生成
key 的策略如果非要用的话我们最好自己重写一下,带上方法名字等类似于如下代码:@Componentpublicclass MyKeyGenerator extends SimpleKeyGenerator { 。
@OverridepublicObject generate(Object target, Method method, Object… params) { Object generate =
super.generate(target, method, params); String format = MessageFormat.format(“{0}{1}{2}”, method.toGenericString(), generate);
return format; } 自定义key我们可以通过 Spring 的EL表达式来指定我们的 key 这里的EL表达式可以使用方法参数及它们对应的属性使用方法参数时我们可以直接使用“ #参数名
”或者“ #p参数index ”这也是我们比较推荐的做法:@Cacheable(value=”user”, key=”#id”)public UserDTO getUserById(Long id) { UserDTO userDTO = new UserDTO(); userDTO.setUserName(
“java金融”); return userDTO; } @Cacheable(value=”user”, key=”#p0″)public UserDTO getUserById1(
Long id) { returnnull; } @Cacheable(value=”user”, key=”#userDTO.id”)public UserDTO getUserById2(UserDTO userDTO) {
returnnull; } @Cacheable(value=”user”, key=”#p0.id”)public UserDTO getUserById3(UserDTO userDTO) {
returnnull; } @CachePut@CachePut 指定的属性是和 @Cacheable 一样的,但是它们两个是有区别的, @CachePut 标注的方法不会先去查询缓存是否有值,而是每次都会先去执行该方法,然后把结果返回,并且结果也会缓存起来。
为什么是这样的一个流程我们可以去看看它的源码关键代码就是这一行, Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation
.class));当我们使用方法上有 @Cacheable 注解的时候在 contexts 里面会把 CacheableOperation 加入进去,只有contexts.get(CacheableOperation.class)取到的内容不为空的话,才会去从缓存里面取内容,否则的话
cacheHit 会直接返回 null 至于contexts什么时候加入CacheableOperation的话我们看下 SpringCacheAnnotationParser#parseCacheAnnotations。
这个方法就会明白的具体的源码就不展示了,感兴趣的可以自己去翻@CacheEvict把缓存中数据删除,用法跟前面两个注解差不多有value和key属性,需要注意一点的是它多了一个属性 beforeInvocation。
beforeInvocation 这个属性需要注意下它的默认值是false,false代表的意思是在执调用方法之前不删除缓存,只有方法执行成功之后才会去删除缓存设置为 true 的话调用方法之前会去删除一下缓存,方法执行成功之后还会去调用删除缓存这样就是双删了。
如果方法执行异常的话就不会去删除缓存allEntriefalsetrue@Caching这是一个组合注解集成了上面三个注解,有三个属性: cacheable、put和evict ,分别用于来指定 @Cacheable
、 @CachePut 和 @CacheEvict 小结第二种方式是侵入式的,它的实现原理也比较简单就是通过切面的方法拦截器来实现,拦截所有的方法,它的核心代码如下:看起来就跟我们的业务代码差不了多少,感兴趣的也可以去瞅一瞅。
if (contexts.isSynchronized()) { CacheOperationContext context = contexts.get(CacheableOperation.class
).iterator().next(); if (isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) { Object key = generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT); Cache cache = context.getCaches().iterator().next();
try { return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker)))); }
catch (Cache.ValueRetrievalException ex) { // The invoker wraps any Throwable in a ThrowableWrapper instance so we
// can just make sure that one bubbles up the stack.throw (CacheOperationInvoker.ThrowableWrapper) ex.getCause(); } }
else { // No caching required, only call the underlying methodreturn invokeOperation(invoker); } }
// Process any early evictions// beforeInvocation 属性是否为true,如果是true就删除缓存 processCacheEvicts(contexts.
get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT);// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));// Collect puts from any @Cacheable miss, if no cached item is found
List cachePutRequests = new LinkedList<>(); if (cacheHit == null) { collectPutRequests(contexts.
get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests); } Object cacheValue; Object returnValue;
if (cacheHit != null && !hasCachePut(contexts)) { // If there are no put requests, just use the cache hit
cacheValue = cacheHit.get(); returnValue = wrapCacheValue(method, cacheValue); } else {
// Invoke the method if we dont have a cache hit returnValue = invokeOperation(invoker); cacheValue = unwrapReturnValue(returnValue); }
// Collect any explicit @CachePuts collectPutRequests(contexts.get(CachePutOperation.class), cacheValue
, cachePutRequests);// Process any collected put requests, either from @CachePut or a @Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) { cachePutRequest.apply(cacheValue); }
// Process any late evictions processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);
return returnValue; } 结束由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容