springboot增加注解缓存@Cacheable的实现
程序员文章站
2022-06-16 11:45:31
目录springboot增加注解缓存@cacheable业务层使用配置@cacheable注解的属性使用cachenames和valuekeykeygeneratorkeygeneratorcondi...
springboot增加注解缓存@cacheable
业务层使用
@cacheable(value = "dictionary#1800", key = "#root.targetclass.simplename +':'+ #root.methodname +':'+ #code") public object findbycode(string code) { //业务 }
配置
import org.springframework.cache.cache; import org.springframework.data.redis.cache.rediscache; import org.springframework.data.redis.cache.rediscachemanager; import org.springframework.data.redis.core.redisoperations; import java.util.concurrent.concurrenthashmap; import java.util.concurrent.concurrentmap; public class myrediscachemanager extends rediscachemanager { /** * 过期时间分隔符 */ private static final string ttlseparator = "#"; private final concurrentmap<string, cache> cachemap = new concurrenthashmap(16); /** * 过期时间, 单位为 秒 */ private long defaultexpiration = 0; public myrediscachemanager(redisoperations redisoperations) { super(redisoperations); } @override public cache getcache(string name) { long expiredtime = defaultexpiration; if (name.contains(ttlseparator)) { string[] split = name.split(ttlseparator); string cachename = split[0]; try { expiredtime = double.valueof(split[1]).longvalue(); } catch (exception e) { e.printstacktrace(); } cache cache = this.cachemap.get(name); if (cache != null) { return cache; } else { synchronized (this.cachemap) { cache = this.cachemap.get(name); if (cache == null) { cache = new rediscache(cachename, null, super.getredisoperations(), expiredtime); if (cache != null) { cache = this.decoratecache(cache); this.cachemap.put(name, cache); } } return cache; } } } return super.getcache(name); } }
import com.fasterxml.jackson.annotation.jsontypeinfo; import com.fasterxml.jackson.databind.objectmapper; import org.springframework.cache.cachemanager; import org.springframework.cache.annotation.cacheconfig; import org.springframework.cache.annotation.cachingconfigurersupport; import org.springframework.cache.annotation.enablecaching; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.serializer.genericjackson2jsonredisserializer; import org.springframework.data.redis.serializer.stringredisserializer; @cacheconfig @configuration @enablecaching public class redisconfig extends cachingconfigurersupport { @bean public cachemanager cachemanager(redistemplate redistemplate) { //设置序列化key的实例化对象 redistemplate.setkeyserializer(new stringredisserializer()); //设置序列化value的实例化对象 objectmapper mapper = new objectmapper(); mapper.findandregistermodules(); mapper.enabledefaulttyping(objectmapper.defaulttyping.non_final, jsontypeinfo.as.property); genericjackson2jsonredisserializer serializer = new genericjackson2jsonredisserializer(mapper); redistemplate.setvalueserializer(serializer); myrediscachemanager mrc = new myrediscachemanager(redistemplate); return mrc; } }
@cacheable注解的属性使用
cachenames和value
指定缓存组件的名字,通过下面代码可以看出可以将返回结果放在哪个缓存中,可以通过数组的方式指定多个缓存
/** * alias for {@link #cachenames}. */ @aliasfor("cachenames") string[] value() default {}; /** * names of the caches in which method invocation results are stored. * <p>names may be used to determine the target cache (or caches), matching * the qualifier value or bean name of a specific bean definition. * @since 4.2 * @see #value * @see cacheconfig#cachenames */ @aliasfor("value") string[] cachenames() default {};
key
缓存数据的时候使用的key,它是用来指定对应的缓存,模拟使用方法参数值作为key的值。也可以使用spel表达式的值来指定
/** * spring expression language (spel) expression for computing the key dynamically. * <p>default is {@code ""}, meaning all method parameters are considered as a key, * unless a custom {@link #keygenerator} has been configured. * <p>the spel expression evaluates against a dedicated context that provides the * following meta-data: * <ul> * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for * references to the {@link java.lang.reflect.method method}, target object, and * affected cache(s) respectively.</li> * <li>shortcuts for the method name ({@code #root.methodname}) and target class * ({@code #root.targetclass}) are also available. * <li>method arguments can be accessed by index. for instance the second argument * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. arguments * can also be accessed by name if that information is available.</li> * </ul> */ string key() default "";
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodname | root object | 被调用的方法名称 | #root.methodname |
method | root object | 被调用的方法 | #root.method.name |
target | root object | 当前被调用的目标对象 | #root.target |
targetclass | root object | 当前被调用的目标对象类 | #root.targetclass |
args | root object | 被调用方法的参数列表#root.args[0] | |
caches | root object | 调用的缓存列表 | #root.caches[0].name |
argument name | evaluation context | 方法的参数名称可以直接使用#参数名 | #p0,#a0等等 |
result | evaluation context | 执行方法后的返回值 | #result |
可以通过这个参数提示列表看看到这个key所支持的root object对象有哪些,通过这样的方式可以指定对应的key值。
keygenerator
这个是表示指定的key的生成器,当然在之前分享中我们说过一个简单的key的生成策略。这里我们还可以通过自定的方式来实现这个key的生成策略。
keygenerator
这个是表示指定的key的生成器,当然在之前分享中我们说过一个简单的key的生成策略。这里我们还可以通过自定的方式来实现这个key的生成策略。
import org.springframework.cache.interceptor.keygenerator; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import java.lang.reflect.method; import java.util.arrays; @configuration public class mycacheconfig { @bean("mykeygenerator") public keygenerator keygenerator(){ return new keygenerator() { @override public object generate(object target, method method, object... params) { return method.getname()+"["+ arrays.aslist(params).tostring()+"]"; } }; } }
在使用的时候可以通过一下的方式进行配置
@cacheable(cachenames = {"emp"},keygenerator = "mykeygenerator")
cachemanager指定缓存管理器 /** * the bean name of the custom {@link org.springframework.cache.cachemanager} to use to * create a default {@link org.springframework.cache.interceptor.cacheresolver} if none * is set already. * <p>mutually exclusive with the {@link #cacheresolver} attribute. * @see org.springframework.cache.interceptor.simplecacheresolver * @see cacheconfig#cachemanager */ string cachemanager() default ""; /** * the bean name of the custom {@link org.springframework.cache.interceptor.cacheresolver} * to use. * @see cacheconfig#cacheresolver */ string cacheresolver() default "";
condition
指定复合条件的情况下才缓存。也可以通过spel表达式进行设置。这个配置规则和上面表格中的配置规则是相同的。
/** * spring expression language (spel) expression used for making the method * caching conditional. * <p>default is {@code ""}, meaning the method result is always cached. * <p>the spel expression evaluates against a dedicated context that provides the * following meta-data: * <ul> * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for * references to the {@link java.lang.reflect.method method}, target object, and * affected cache(s) respectively.</li> * <li>shortcuts for the method name ({@code #root.methodname}) and target class * ({@code #root.targetclass}) are also available. * <li>method arguments can be accessed by index. for instance the second argument * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. arguments * can also be accessed by name if that information is available.</li> * </ul> */ string condition() default "";
unless(除非)
当这个条件为true的时候,方法的返回值就不会被缓存。
/** * spring expression language (spel) expression used to veto method caching. * <p>unlike {@link #condition}, this expression is evaluated after the method * has been called and can therefore refer to the {@code result}. * <p>default is {@code ""}, meaning that caching is never vetoed. * <p>the spel expression evaluates against a dedicated context that provides the * following meta-data: * <ul> * <li>{@code #result} for a reference to the result of the method invocation. for * supported wrappers such as {@code optional}, {@code #result} refers to the actual * object, not the wrapper</li> * <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for * references to the {@link java.lang.reflect.method method}, target object, and * affected cache(s) respectively.</li> * <li>shortcuts for the method name ({@code #root.methodname}) and target class * ({@code #root.targetclass}) are also available. * <li>method arguments can be accessed by index. for instance the second argument * can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. arguments * can also be accessed by name if that information is available.</li> * </ul> * @since 3.2 */ string unless() default "";
sync
是否异步
/** * synchronize the invocation of the underlying method if several threads are * attempting to load a value for the same key. the synchronization leads to * a couple of limitations: * <ol> * <li>{@link #unless()} is not supported</li> * <li>only one cache may be specified</li> * <li>no other cache-related operation can be combined</li> * </ol> * this is effectively a hint and the actual cache provider that you are * using may not support it in a synchronized fashion. check your provider * documentation for more details on the actual semantics. * @since 4.3 * @see org.springframework.cache.cache#get(object, callable) */ boolean sync() default false;
注意
在使用这个属性的时候,当这个属性为true的时候,unless属性是不能使用的。
{@link #unless()} is not supported
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
推荐阅读
-
SpringBoot使用AOP+注解实现简单的权限验证的方法
-
浅谈基于SpringBoot实现一个简单的权限控制注解
-
SpringBoot使用Redis缓存的实现方法
-
SpringBoot2.3整合redis缓存自定义序列化的实现
-
基于spring的缓存注解实现
-
Springboot自定义注解实现简单的接口权限控制,替代Shiro/SpringSecurity
-
springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)
-
SpringBoot @Validated注解实现参数分组校验的方法实例
-
SpringBoot 03——深入SpringBoot底层源码架构分析引导类注解的具体实现
-
SpringBoot中自定义注解实现参数非空校验的示例