Spirng cache ,redis,ehcache
Spirng cache(4.1.1)
SpringCache并非某一种Cache实现的技术,SpringCache是一种缓存实现的通用技术,基于Spring提供的Cache框架,让开发者更容易将自己的缓存实现高效便捷的嵌入到自己的项目中。当然,SpringCache也提供了本身的简单实现NoOpCacheManager、ConcurrentMapCacheManager 等。通过SpringCache,可以快速嵌入自己的Cache实现。
springcache 相关的注解
1.@Cacheable
标记在方法或者类上,对于key 已经存在的直接返回
2.@CacheEvict
标记在方法或者类上,对于key 已经存在的直接清除
3.@CachePut
标记在方法或者类上,强制执行方法后将结果存入缓存
4.@Caching
标记在方法或者类上 Caching注解是Cacheable、CachePut、CacheEvict的组合注解
5.@CacheConfig
一个类级别的注解。用于统一配置该类下的cacheNames;keyGenerator;cacheManager;cacheResolver;
1.入口类CacheInterceptor
该类实现了MethodInterceptor故在调用时会经过该方法。
若存在 <cache:annotation-driven />
则在启动时会注册CacheInterceptor以及其他项具体可查询AnnotationDrivenCacheBeanDefinitionParser类
入口处先对 invocation 进行一次封装,封装成CacheOperationInvoker
此封装只是为了进行异常的处理
实际处理是
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
2。实际处理execute
该方法位于CacheInterceptor父类CacheAspectSupport
首先判断spring的cache组件是否初始化成功,不成功则直接运行方法。
初始化成功则先取获取该方法(类)上的(cache类)注解集合
Collection<CacheOperation> operations = getCacheOperationSource().getCacheOperations(method, targetClass);
该方法内使用了map,存储已经获取过的方法的注解集合,若map中不存在则通过以下方法获取
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
获取顺序 1.方法注解 2.class注解3接口或者父类上方法的注解4,接口或者父类上的注解。
任意一次获取到就return
3.根据集合执行具体操作
private Object execute(CacheOperationInvoker invoker, CacheOperationContexts contexts) {
// 如果有 @CacheEvict 注解,并且 beforeInvocation==true 执行 cache.evict(key);
processCacheEvicts(contexts.get(CacheEvictOperation.class), true, ExpressionEvaluator.NO_RESULT);
// Cacheable 如果条件成立,则获取缓存数据
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
//不存在缓存时 获取所有条件成立的Cacheable注解的key和注解放在cachePutRequests中后续使用
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class), ExpressionEvaluator.NO_RESULT, cachePutRequests);
}
//有值说明不需执行真正的业务逻辑
//(执行业务逻辑有2种情况1.没有缓存,2 有cachePut操作)
Cache.ValueWrapper result = null;
// 没有满足 condition 的 @Cacheable 操作,且 当前没有满足condition的 @CachePut 操作
//1.如果有需要更新的操作 则result 应该为null(执行真正的业务逻辑)
//2.如果不存在需要更新的操作则 根据前面从缓存中获取到的值判断是不是需要执行真正的业务逻辑
if (cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
result = cacheHit;
}
//当不存在缓存时 注解调用方法获取结果
if (result == null) {
result = new SimpleValueWrapper(invokeOperation(invoker));
}
// 获取 符合条件的CachePut
collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);
// 缓存数据(未进行缓存的@Cacheable或是@CachePut)
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(result.get());
}
// 处理 @CacheEvict 请求
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());
return result.get();
}
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
此方法内部获取时或获取当前的cacheManger(redis,ehcache等) 进行操作
优缺点
优点
1、方便快捷高效,可直接嵌入多个现有的cache实现,简写了很多代码,可观性非常强
缺点
1、内部调用,非public方法上使用注解,会导致缓存无效。由于SpringCache是基于Spring AOP的动态代理实现,由于代理本身的问题,当同一个类中调用另一个方法,会导致另一个方法的缓存不能使用,这个在编码上需要注意,避免在同一个类中这样调用。如果非要这样做,可以通过再次代理调用,如((Category)AopContext.currentProxy()).get(category)这样避免缓存无效
2、不能支持多级缓存设置,如默认到本地缓存取数据,本地缓存没有则去远端缓存取数据,然后远程缓存取回来数据再存到本地缓存。
ehcache
官方文档http://www.ehcache.org
配置好对应的xml 或者config
ehcache xml配置详解可参考该文章(2.X版本)
https://www.iteye.com/blog/elim-2113728
https://my.oschina.net/u/2608182/blog/890916
3.X版本
https://blog.csdn.net/weixin_34038652/article/details/92334486
以下为根据 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
生成的xml 具体效果暂未使用过 后续再加
<?xml version="1.0" encoding="UTF-8"?>
<!--用XMLSpy v2013 sp1产生的 XML文件(http://www.altova.com)-->
<ehcache:config xsi:schemaLocation="http://www.ehcache.org/v3 ehcache.xsd" xmlns:ehcache="http://www.ehcache.org/v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ehcache:default-serializers>
<ehcache:serializer type="String">String</ehcache:serializer>
<ehcache:serializer type="String">String</ehcache:serializer>
</ehcache:default-serializers>
<ehcache:default-copiers>
<ehcache:copier type="String">String</ehcache:copier>
<ehcache:copier type="String">String</ehcache:copier>
</ehcache:default-copiers>
<ehcache:persistence directory="String"/>
<ehcache:thread-pools>
<ehcache:thread-pool alias="String" default="false" min-size="1" max-size="2"/>
<ehcache:thread-pool alias="String" default="false" min-size="1" max-size="2"/>
</ehcache:thread-pools>
<ehcache:event-dispatch thread-pool="String"/>
<ehcache:write-behind thread-pool="String"/>
<ehcache:heap-store>
<ehcache:max-object-graph-size>1000</ehcache:max-object-graph-size>
<ehcache:max-object-size unit="B">9223372036854775807</ehcache:max-object-size>
</ehcache:heap-store>
<ehcache:disk-store thread-pool="String"/>
<ehcache:cache alias="String" uses-template="ID_1">
<ehcache:key-type serializer="String" copier="String">java.lang.Object</ehcache:key-type>
<ehcache:value-type serializer="String" copier="String">java.lang.Object</ehcache:value-type>
<ehcache:expiry>
<ehcache:class>String</ehcache:class>
</ehcache:expiry>
<ehcache:eviction-advisor>String</ehcache:eviction-advisor>
<ehcache:loader-writer>
<ehcache:class>String</ehcache:class>
<ehcache:write-behind concurrency="1" size="2147483647" thread-pool="String">
<ehcache:batching batch-size="2" coalesce="false">
<ehcache:max-write-delay unit="seconds">2</ehcache:max-write-delay>
</ehcache:batching>
</ehcache:write-behind>
</ehcache:loader-writer>
<ehcache:listeners dispatcher-thread-pool="String" dispatcher-concurrency="8">
<ehcache:listener>
<ehcache:class>String</ehcache:class>
<ehcache:event-firing-mode>SYNCHRONOUS</ehcache:event-firing-mode>
<ehcache:event-ordering-mode>UNORDERED</ehcache:event-ordering-mode>
<ehcache:events-to-fire-on>CREATED</ehcache:events-to-fire-on>
<ehcache:events-to-fire-on>REMOVED</ehcache:events-to-fire-on>
</ehcache:listener>
<ehcache:listener>
<ehcache:class>String</ehcache:class>
<ehcache:event-firing-mode>ASYNCHRONOUS</ehcache:event-firing-mode>
<ehcache:event-ordering-mode>UNORDERED</ehcache:event-ordering-mode>
<ehcache:events-to-fire-on>UPDATED</ehcache:events-to-fire-on>
<ehcache:events-to-fire-on>EXPIRED</ehcache:events-to-fire-on>
</ehcache:listener>
</ehcache:listeners>
<ehcache:heap unit="entries">2</ehcache:heap>
<ehcache:heap-store-settings>
<ehcache:max-object-graph-size>1000</ehcache:max-object-graph-size>
<ehcache:max-object-size unit="B">9223372036854775807</ehcache:max-object-size>
</ehcache:heap-store-settings>
<ehcache:disk-store-settings thread-pool="String" writer-concurrency="1"/>
</ehcache:cache>
<ehcache:cache alias="String" uses-template="ID_1">
<ehcache:key-type serializer="String" copier="String">java.lang.Object</ehcache:key-type>
<ehcache:value-type serializer="String" copier="String">java.lang.Object</ehcache:value-type>
<ehcache:expiry>
<ehcache:class>String</ehcache:class>
</ehcache:expiry>
<ehcache:eviction-advisor>String</ehcache:eviction-advisor>
<ehcache:loader-writer>
<ehcache:class>String</ehcache:class>
<ehcache:write-behind concurrency="1" size="2147483647" thread-pool="String">
<ehcache:batching batch-size="2" coalesce="false">
<ehcache:max-write-delay unit="seconds">2</ehcache:max-write-delay>
</ehcache:batching>
</ehcache:write-behind>
</ehcache:loader-writer>
<ehcache:listeners dispatcher-thread-pool="String" dispatcher-concurrency="8">
<ehcache:listener>
<ehcache:class>String</ehcache:class>
<ehcache:event-firing-mode>SYNCHRONOUS</ehcache:event-firing-mode>
<ehcache:event-ordering-mode>UNORDERED</ehcache:event-ordering-mode>
<ehcache:events-to-fire-on>UPDATED</ehcache:events-to-fire-on>
<ehcache:events-to-fire-on>UPDATED</ehcache:events-to-fire-on>
</ehcache:listener>
<ehcache:listener>
<ehcache:class>String</ehcache:class>
<ehcache:event-firing-mode>ASYNCHRONOUS</ehcache:event-firing-mode>
<ehcache:event-ordering-mode>UNORDERED</ehcache:event-ordering-mode>
<ehcache:events-to-fire-on>UPDATED</ehcache:events-to-fire-on>
<ehcache:events-to-fire-on>EVICTED</ehcache:events-to-fire-on>
</ehcache:listener>
</ehcache:listeners>
<ehcache:heap unit="entries">2</ehcache:heap>
<ehcache:heap-store-settings>
<ehcache:max-object-graph-size>1000</ehcache:max-object-graph-size>
<ehcache:max-object-size unit="B">9223372036854775807</ehcache:max-object-size>
</ehcache:heap-store-settings>
<ehcache:disk-store-settings thread-pool="String" writer-concurrency="1"/>
</ehcache:cache>
</ehcache:config>
<?xml version="1.0" encoding="UTF-8"?>
<!--用XMLSpy v2013 sp1产生的 XML文件(http://www.altova.com)-->
<jsr107:defaults default-template="ID_1" jsr-107-compliant-atomics="true" enable-management="true" enable-statistics="true" xsi:schemaLocation="http://www.ehcache.org/v3/jsr107 ehcache.xsd" xmlns:jsr107="http://www.ehcache.org/v3/jsr107" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<jsr107:cache name="ID_1" template="ID_1"/>
<jsr107:cache name="ID_2" template="ID_1"/>
</jsr107:defaults>
另有一份xsd暂不知何用(可能用于事务部分xml配置的解析) 暂且记录
https://www.cnblogs.com/yaohonv/archive/2012/02/10/JTA-Ehcache.html
<!--
~ Copyright Terracotta, Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<xs:schema xmlns:tx="http://www.ehcache.org/v3/tx" xmlns:eh="http://www.ehcache.org/v3" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0" elementFormDefault="qualified" targetNamespace="http://www.ehcache.org/v3/tx">
<xs:import namespace="http://www.ehcache.org/v3"/>
<xs:element name="xa-store" type="tx:xa-store-config-type" substitutionGroup="eh:service-configuration"/>
<xs:element name="jta-tm" type="tx:jta-tm-type" substitutionGroup="eh:service-creation-configuration"/>
<xs:complexType name="xa-store-config-type">
<xs:attribute name="unique-XAResource-id" type="xs:string" use="required"/>
</xs:complexType>
<xs:complexType name="jta-tm-type">
<xs:attribute name="transaction-manager-lookup-class" type="xs:string" use="required"/>
</xs:complexType>
</xs:schema>
Redis
redis xml配置
https://blog.csdn.net/Monstar_hu/article/details/80459449
上部分说到
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
通过实际cache进行各自的操作
而redis此处获取到的配置的就是 RedisCache,在之前的操作中RedisCache对象的 RedisOperations属性以及被赋值为RedisTemplate即我们自己配置的bean。
最后 直接根据RedisTemplate -> JedisConnection-> Jedis 进行缓存的。该部分后续新写一篇进行记录。
Redis 序列化方式(后续详细记录暂且记录) https://blog.csdn.net/sinat_35821285/article/details/82828795