Spirng cache

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

发布了21 篇原创文章 · 获赞 6 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/soulonlyhlh/article/details/104143912
今日推荐