File: docs/EN/AdvancedCacheAPI.md
CacheBuilder
The CacheBuilder provide a way to construct Cache instance use your own code, See Here.CacheBuilder are useful if you work without Spring, otherwise you may not use it directly.
asynchronous API
All CacheResult returned by uppercase method support asynchronous access (since 2.2).
Presently asynchronous result only provide in redis-lettuce implementation.
Other implementations such as Tair, Jedis will block during uppercase method call.
But all the api are same.
For example:
CacheGetResult r = cache.GET(userId);If you use Tair, Jedis the GET operation will block until cache access finished.
However the GET method will return immediately if you use lettuce to access redis,
any following call of r.isSuccess() or r.getValue() or r.getMessage() will block. To avoid this you can:
CompletionStage<ResultData> future = r.future();
future.thenRun(() -> {
if(r.isSuccess()){
System.out.println(r.getValue());
}
});The above code will execute callback in the thread which execute the asynchronous operation.CompletionStage is a new feature in Java 8, read related documents if you are not familiar with it.
Note do not call any block method in the callback, since the callback is probably run in event-loop thread.
Some lowercase API can also get the advantage of asynchronous capability since they have no return value (in a asynchronous enabled backend such as lettuce).
For instance put and removeAll will return immediately, but get will not because get method need return a value.
Auto load(read through)
LoadingCache provide auto load capability (since 2.2). It is based on decorator pattern and implements Cache interface.
If a CacheBuilder has a loader, then its buildCache method will return a LoadingCache wrapper.
For example :
Cache<Long,UserDO> userCache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
.loader(key -> loadUserFromDatabase(key))
.buildCache();The get and getAll method of LoadingCache will call the loader when cache miss.
If any exception throws in the loader, get and getAll will throw CacheInvokeException.
Notice:
- uppercase method such as GET and GET_ALL only operate with cache and do not invoke the loader.
- loader should be install on
MultiLevelCacheif you use multi level cache, do not install it on the cache underneath.
Unfortunately, we can't set the loader on @CreateCache because only constant is permit for the attribute of an annotation.
So we use the follow code instead:
@CreateCache
private Cache<Long,UserDO> userCache;
@PostConstruct
public void init(){
userCache.config().setLoader(this::loadUserFromDatabase);
}@CreateCache always return a LoadingCache wrapper, so we can set a loader in the init method and take effect immediately.
Auto refreshment
The RefreshCache provide auto refreshment capability (since 2.2).
It is based on decorator pattern and implements Cache interface.
The buildCache method of CacheBuilder will return a RefreshCache wrapper when loader and refreshPolicy are both be set.
CacheBuilder usage:
RefreshPolicy policy = RefreshPolicy.newPolicy(1, TimeUnit.MINUTES)
.stopRefreshAfterLastAccess(30, TimeUnit.MINUTES);
Cache<String, Long> orderSumCache = LinkedHashMapCacheBuilder
.createLinkedHashMapCacheBuilder()
.loader(key -> loadOrderSumFromDatabase(key))
.refreshPolicy(policy)
.buildCache();The above code specify that every key-value pair should refresh every 1 minute since first access.
The refreshment of one key-value pair stops if this key does not be access in 30 minutes.
If the backend cache system is a remote cache (or MultiLevelCache with a remote cache as last layer),
the refreshment is global exclusive, so it avoid two or more servers refresh same key concurrently (implements using tryLock in Cache).
Similar with LoadingCache, we init refresh policy in the init method when using with @CreateCache:
@CreateCache
private Cache<String, Long> orderSumCache;
@PostConstruct
public void init(){
RefreshPolicy policy = RefreshPolicy.newPolicy(1, TimeUnit.MINUTES)
.stopRefreshAfterLastAccess(30, TimeUnit.MINUTES);
orderSumCache.config().setLoader(this::loadOrderSumFromDatabase);
orderSumCache.config().setRefreshPolicy(policy);
}File: docs/EN/Builder.md
Annotations such as @Cached and @CreateCache are based on Spring Framework 4.0 or above.
You can use JetCache API to create, manage, monitor Cache instance.
Create Cache
Similar to guava/caffeine cache. For example, the below code create a LinkedHashMapCache instance:
Cache<String, Integer> cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
.limit(100)
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();Create RedisCache (using jedis):
GenericObjectPoolConfig pc = new GenericObjectPoolConfig();
pc.setMinIdle(2);
pc.setMaxIdle(10);
pc.setMaxTotal(10);
JedisPool pool = new JedisPool(pc, "localhost", 6379);
Cache<Long, OrderDO> orderCache = RedisCacheBuilder.createRedisCacheBuilder()
.keyConvertor(Fastjson2KeyConvertor.INSTANCE)
.valueEncoder(JavaValueEncoder.INSTANCE)
.valueDecoder(JavaValueDecoder.INSTANCE)
.jedisPool(pool)
.keyPrefix("orderCache")
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();Note: JetCache 2.8.x enables the deserialization security filter by default. If your cached values contain custom classes (e.g.
OrderDOabove), you need to configure the filter allow list before creating the cache, otherwise deserialization will fail:javaDecodeFilter.getDefault().addAllowPatterns("com.yourcompany.");See the "Deserialization Filter Configuration" section in the configuration docs for details.
Multi level cache
Cache multiLevelCache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder()
.addCache(memoryCache, redisCache)
.expireAfterWrite(100, TimeUnit.SECONDS)
.buildCache();You can even build cache more than two level.
Monitor
Cache orderCache = ...
CacheMonitor orderCacheMonitor = new DefaultCacheMonitor("OrderCache");
orderCache.config().getMonitors().add(orderCacheMonitor); // jetcache 2.2+, or call builder.addMonitor() before buildCache()
// Cache<Long, Order> monitedOrderCache = new MonitoredCache(orderCache, orderCacheMonitor); //before jetcache 2.2
int resetTime = 1;
boolean verboseLog = false;
DefaultCacheMonitorManager cacheMonitorManager = new DefaultCacheMonitorManager(resetTime, TimeUnit.SECONDS, verboseLog);
cacheMonitorManager.add(orderCacheMonitor);
cacheMonitorManager.start();Each CacheMonitor used for exactly one Cache instance.
After start, DefaultCacheMonitorManager outputs statistics every resetTime using slf4j (see Statistics).
The constructor parameter of DefaultCacheMonitor will be used as cache name in output table.
You can add to CacheMonitor to every Cache instance in MultiLevelCache,
so each cache in multi level cache is monitored.
The output format can be customized using this constructor:
public DefaultCacheMonitorManager(int resetTime, TimeUnit resetTimeUnit, Consumer<StatInfo> statCallback)File: docs/EN/CacheAPI.md
Introduce
The core concept of JetCache is the com.alicp.jetcache.Cache(hereinafter called Cache) interface, it provides some API similar like javax.cache.Cache in JSR107.
The reason that JetCache does not implements JSR107 includes:
- We want that the API of JetCache are more simpler and easy to use than JSR107.
- Some operation defined in
javax.cache.Cacheare difficult to implement efficiently in some specific distributed cache system (eg. some atomic operation andremoveAll()). - Implements whole JSR107 needs a lots of work.
JSR107 style API
The follows methods in JetCache Cache interface are same with those in javax.cache.Cache except that
the methods in Cache never throws exception.
V get(K key)
void put(K key, V value);
boolean putIfAbsent(K key, V value); //MultiLevelCache do not support this method
boolean remove(K key);
<T> T unwrap(Class<T> clazz);
Map<K,V> getAll(Set<? extends K> keys);
void putAll(Map<? extends K,? extends V> map);
void removeAll(Set<? extends K> keys);JetCache Cache API
V computeIfAbsent(K key, Function<K, V> loader)
V computeIfAbsent(K key, Function<K, V> loader, boolean cacheNullWhenLoaderReturnNull)
V computeIfAbsent(K key, Function<K, V> loader, boolean cacheNullWhenLoaderReturnNull, long expire, TimeUnit timeUnit)If there is a value associated with the key, return the value,
otherwise use the loader load the value and update the cache, then return the value.
The cacheNullWhenLoaderReturnNull parameter indicate whether null value returned by loader should put into cache.
The expire and timeUnit specifies the TTL (will overrides defaults) of the KV pair when update the cache.
Load time are recorded with these methods.
void put(K key, V value, long expire, TimeUnit timeUnit)The put opperation. expire and timeUnit specifies the TTL (will overrides defaults).
AutoReleaseLock tryLock(K key, long expire, TimeUnit timeUnit)
boolean tryLockAndRun(K key, long expire, TimeUnit timeUnit, Runnable action)Try to get a lock of the key in non-block way.
Return a instance of AutoReleaseLock if there is no lock on the specified key, or else null.
If the Cache is an in-memory implementation, the lock is a local lock in the JVM,
or else it's a non-strict distributed lock.
The expire time of the lock specified by expire and timeUnit.MultiLevelCache use the last level to acquire the lock.
Here is an example:
// use try-with-resource to auto release the lock
try(AutoReleaseLock lock = cache.tryLock("MyKey",100, TimeUnit.SECONDS)){
if(lock != null){
// do something
}
}Here is a simpler way that you never forget if(lock != null):
boolean hasRun = cache.tryLockAndRun("MyKey",100, TimeUnit.SECONDS, () -> {
// do something
});When the cache system is distributed, the tryLock will carefully auto retry when network fails, and it never release a lock that the current machine doesn't hold. Using tryLock or tryLockAndRun are much easier than make your own lock based on a cache system.
Be keep in mind that the distributed lock based on a cache system is non-strict,
if you need strict distributed lock you should consider other framework like Zoo Keeper.
Upper case API
Operation like V get(K key) are convenient but it can not tell more information when it returns null.
So JetCache provide some more operation which return a CacheResult object like belows:
CacheGetResult<V> GET(K key);
MultiGetResult<K, V> GET_ALL(Set<? extends K> keys);
CacheResult PUT(K key, V value);
CacheResult PUT(K key, V value, long expireAfterWrite, TimeUnit timeUnit);
CacheResult PUT_ALL(Map<? extends K, ? extends V> map);
CacheResult PUT_ALL(Map<? extends K, ? extends V> map, long expireAfterWrite, TimeUnit timeUnit);
CacheResult REMOVE(K key);
CacheResult REMOVE_ALL(Set<? extends K> keys);
CacheResult PUT_IF_ABSENT(K key, V value, long expireAfterWrite, TimeUnit timeUnit);The name of these method are all uppercase. The usage are more complex and powerful:
CacheGetResult<OrderDO> r = cache.GET(orderId);
if( r.isSuccess() ){
OrderDO order = r.getValue();
} else if (r.getResultCode() == CacheResultCode.NOT_EXISTS) {
System.out.println("cache miss:" + orderId);
} else if(r.getResultCode() == CacheResultCode.EXPIRED) {
System.out.println("cache expired:" + orderId));
} else {
System.out.println("cache get error:" + orderId);
}File: docs/EN/Compatibility.md
spring compatibility
jetcache tested with below spring/spring-boot versions
| jetcache | spring | spring boot | comments |
|---|---|---|---|
| 2.5 | 4.0.8.RELEASE~5.1.1.RELEASE | 1.1.9.RELEASE~2.0.5.RELEASE | |
| 2.6 | 5.0.4.RELEASE~5.2.4.RELEASE | 2.0.0.RELEASE~2.2.5.RELEASE | jetcache-redis depends on jedis3.1.0, spring-data(jedis, boot version<=2.1.X) depends on jedis2.9.3, can't used together |
| 2.7 | 5.2.4.RELEASE~5.3.23 | 2.2.5.RELEASE~2.7.5 | jetcache-redis depends on jedis4, spring-data(jedis) depends on jedis3, can't used together |
| 2.7.4 | 5.2.4.RELEASE~6.2.18 | 2.2.5.RELEASE~3.5.14 | can also support Spring 7/Spring Boot 4, but the BOM defines Spring 6/Spring Boot 3 by default |
| 2.8 | 6.x~7.0.7 | 3.x~4.0.6 | requires Java 17+; BOM defaults to Spring Framework 7.0.7 / Spring Boot 4.0.6 / Spring Data Redis 4.0.5 / SLF4J 2.x |
compatible change notes
2.8.0
Java 17 is now the minimum required version
areaInCacheNamedefault value is nowfalse(wastruein versions prior to 2.8.0).kryo4 is no longer supported,
com.esotericsoftware:kryois upgraded to 5.x. TheKRYOconstant inSerialPolicynow uses kryo5 implementation internally. kryo4 serialized data is not compatible with kryo5, wait for old cache entries to expire or clear cache before upgradingRemoved fastjson1 support,
fastjsonkey convertor now uses fastjson2 internally. If you need fastjson1, add the dependency yourself and implement a custom KeyConvertorRemoved Spring XML namespace support (
<jetcache:xxx>tags in XML configuration are no longer available)Added deserialization filter mechanism (enabled by default). This is a breaking change — if your cached values contain custom classes not in the default allowed list, deserialization (or serialization) will fail immediately after upgrading.
Upgrade steps: Since older versions do not have this configuration option, pre-configuration before upgrading is not possible. Two recommended approaches:
Option 1: Add
decodeFilterAllowPatternsconfiguration at the same time as upgrading JetCache, including the package names of your custom classes in the allow list. For example:yamljetcache: decodeFilterAllowPatterns: - com.yourcompany.Option 2: Disable the filter during upgrade (same behavior as 2.7):
yamljetcache: decodeFilterEnabled: falseSee the "Deserialization Filter Configuration" section in the configuration docs for the list of default allowed packages and detailed setup instructions.
2.7.4
- use spring-boot 3.1.3, spring-framework 6.0.11, slf4j-api 2.x as default
- remove javax.annotation:javax.annotation-api, if you use @PostConstruct, you may need to add this dependency by yourself
2.7.2
- update encoder/decoder of redisson, not compatible with 2.7.1
2.7.0
- jetcache-redis depends on jedis4,springdata(jedis) depends on jedis3, can't use together
- encoder/decoder now support kryo4 and kryo5, in yml "kryo" is kryo4,"kryo5" is kryo5. the kryo4 and kryo5 is not compatible.
- in maven kryo4 is com.esotericsoftware:kryo, kryo5 is com.esotericsoftware.kryo:kryo5
- kryo4 and kryo5 can be used together
- notice that version of com.esotericsoftware:kryo can be set to 5.x.x
- use lettuce to connect redis cluster need specify "mode=cluster" in yml
- default key convertor change to "fastjson2", fastjson2 and fastjson can be used together, fastjson(not fastjson2)/kryo/kryo5/mvel is now optional in maven
- if not use spring boot, add
@Import(JetCacheBaseBeans.class), and remove old configProvider bean definition. see docs for detail example. - change GlobalCacheConfig.areaInCacheName default value to false (has bug, default value may still be true), need to add areaInCacheName=false
2.6.0
- GET/GET_ALL method of RefreshCache will not trigger auto refresh
- lettuce 4 is not supported
- jedis 2.9 is not supported
2.5.0
- ClassCastException may occurs when upgrade directly from versions <=2.3.3 and MultiLevelCache(or cacheType=CacheType.BOTH) is used. To solve this problem, upgrade to 2.4.4 and deploy it to product env first, then upgrade to 2.5.0 or above.
- Annotations on sub classes will override annotations on interfaces and super class.
File: docs/EN/Config.md
Here is an example of yml config file in Spring Boot:
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
hidePackages: com.alibaba
local:
default:
type: caffeine
limit: 100
keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
expireAfterWriteInMillis: 100000
otherArea:
type: linkedhashmap
limit: 100
keyConvertor: none
expireAfterWriteInMillis: 100000
remote:
default:
type: redis
keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
broadcastChannel: projectA
valueEncoder: java #other choose:kryo/kryo5
valueDecoder: java #other choose:kryo/kryo5
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${redis.host}
port: ${redis.port}
otherArea:
type: redis
keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
broadcastChannel: projectA
valueEncoder: java #other choose:kryo/kryo5
valueDecoder: java #other choose:kryo/kryo5
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: ${redis.host}
port: ${redis.port}You can configure GlobalCacheConfig directly without Spring Boot. It's similar. See getting started tutorial.
The description of configuration listed in the below table:
| configuration key | default value | description |
|---|---|---|
| jetcache.statIntervalMinutes | 0 | Specify statistic interval, in minutes. 0 indicate no statistics. |
| jetcache.areaInCacheName | true(2.6-) false(2.7+) | jetcache-anno use cache name as remote cache key prefix, in jetcache 2.4.3 and previous version, it allways add area name in cache name. Since 2.4.4 we have this config item, for compatible reason default value is true. However false value are more reasonable for new project. 2.7 changes default value to false |
| jetcache.useDefaultLocalExpireInMultiLevelCache | false | If set to true, when cacheType is BOTH and localExpire is not explicitly set (including @Cached, @CreateCache annotations and QuickConfig API), the local cache expire time will be the minimum of the local cache builder's expireAfterWriteInMillis and expire. |
| jetcache.hiddenPackages | undefined | The package name startsWith(hiddenPackages) will be cut off in the generated cache instance name. |
| jetcache.[local/remote].${area}.type | undefined | Type of the backend cache system. Can be tair, redis for remote cache ,or linkedhashmap, caffeine for local cache. |
| jetcache.[local/remote].${area}.keyConvertor | fastjson2 | Global config of key convertor. 2.8+ supports key convertor: fastjson2/jackson/jackson3 (fastjson is also available, which uses fastjson2 internally). You can use none only in the case of @CreateCache(cacheType=CacheType.LOCAL), in this situation equals is used to distinguish key. Method caching must specify a keyConvertor |
| jetcache.[local/remote].${area}.valueEncoder | java | Global config of value encoder, only remote cache need it. 2.8+ supports valueEncoder: java/kryo/kryo5 (kryo and kryo5 both use kryo5 implementation) |
| jetcache.[local/remote].${area}.valueDecoder | java | Global config of value decoder, only remote cache need it. 2.8+ supports valueDecoder: java/kryo/kryo5 (kryo and kryo5 both use kryo5 implementation) |
| jetcache.[local/remote].${area}.limit | 100 | Global config of max elements in local memory for each Cache instance. Only local cache need it. |
| jetcache.[local/remote].${area}.expireAfterWriteInMillis | infinity | Global config of write expire time, in millis. |
| jetcache.remote.${area}.broadcastChannel | n/a | jetcahe2.7 support invalidate local cache of other jvm after updatation (cacheType = CacheType.BOTH), this config specify broadcast channel, this feature disabled if not set |
| jetcache.local.${area}.expireAfterAccessInMillis | 0 | Global config of read expire time, in millis. Need jetcache2.2+, only local cache support this feature. 0 indicates disabled read expire feature. |
| jetcache.decodeFilterEnabled | true | Master switch for deserialization filter, enabled by default. Set to false to restore old behavior (NOT recommended) |
| jetcache.decodeFilterAllowPatterns | undefined | User-defined allow patterns appended to the default allow list. Three match modes are supported (see below) |
| jetcache.decodeFilterDenyPatterns | undefined | User-defined deny patterns appended to the default deny list. Deny patterns always take precedence over allow patterns |
The ${area} of the above table is the area attribute of @Cached and @CreateCache. Note that the default value of area attribute of the two annotation is "default".
There are multi place which the write expire time can be set:
- if a method like
putinCacheinterface sets expire, then use it. - if not set in method like
put, use default expire of theCacheinstance - the default expire of the
Cacheinstance can be set in attribute on@CreateCacheor@Cached, if not, JetCache use global configdefaultExpireInMillisdefined in yml(for instance@Cached(cacheType=local)usejetcache.local.default.expireAfterWriteInMillis), if there is not defined yet then use infinity.
Deserialization Filter Configuration
JetCache 2.8.x enables deserialization filter by default. The filter maintains both an allow list and a deny list. The deny list takes the highest priority and cannot be overridden by user-defined allow patterns.
The default allow list:
| Pattern | Match mode | Description |
|---|---|---|
java.lang |
Package match | Direct classes only (e.g. String, Integer), excluding subpackages (reflect, invoke) |
java.util. |
Prefix match | Collections and subpackages (e.g. HashMap, concurrent.ConcurrentHashMap) |
java.time. |
Prefix match | Date/time classes (e.g. LocalDate, Duration) |
java.math |
Package match | BigDecimal, BigInteger, etc. (no subpackages exist) |
java.net |
Package match | URI, URL, etc. Direct classes only, excluding subpackages |
com.alicp.jetcache. |
Prefix match | JetCache internal classes |
If your cached values contain custom classes, you need to configure the filter:
jetcache:
decodeFilterEnabled: true # default true, can set false to disable
decodeFilterAllowPatterns:
- com.example. # prefix match: all classes under com.example and subpackages
- org.myapp.dto # package match: direct classes in org.myapp.dto (no subpackages)
- org.myapp.dto.UserDTO # exact match: only this specific class
decodeFilterDenyPatterns:
- com.example.internal. # block this package and its subpackages
- org.myapp.dto.SecretDTO # block one specific classFilter rules: The built-in deny list includes known deserialization gadget chains (e.g. Commons Collections, Spring AOP, Hibernate, Groovy, JNDI/RMI, C3P0, etc.), dangerous classes like java.lang.Runtime and ProcessBuilder, and JDK internal packages like com.sun. and sun.. Deny patterns cannot be overridden by allow rules. If necessary, you can remove specific deny patterns via DecodeFilter.getDefault().removeDenyPatterns(...) (evaluate security risks yourself).
Pattern matching rules:
- Prefix match (ends with
.): matches all classes in the package and all subpackages. For example,com.example.matchescom.example.Foo,com.example.sub.Bar, etc. - Package match (no trailing
., not a full class name): matches only classes directly in the package, excluding subpackages. For example,com.examplematchescom.example.Foobut notcom.example.sub.Bar. The default allow list uses this mode forjava.langandjava.net. - Exact match (full class name): matches only one specific class. For example,
org.myapp.dto.UserDTOmatches onlyorg.myapp.dto.UserDTO.
Tip: If your custom classes are spread across multiple packages, prefix match (ending with
.) is the most convenient option.
You can also configure programmatically (non-Spring Boot scenario):
DecodeFilter filter = DecodeFilter.getDefault();
filter.addAllowPatterns("com.example.");If a class is blocked during deserialization, an ERROR log is emitted (containing the rejected class name and configuration examples), and an exception is thrown. Kryo and JSON paths throw DecodeFilterException; Java serialization throws InvalidClassException (JDK internal behavior).
Notes:
- JDK dynamic proxy classes (e.g.
jdk.proxy1.$Proxy0) are not in the default allow list. If you cache proxy objects (e.g. Spring AOP proxies), add an allow rule (e.g.jdk.proxy.). - Packages like
java.rmi.,javax.naming.,java.lang.reflect.,javax.script.,javax.management.are in the built-in deny list — adding allow rules cannot override them. Packages likejava.io,java.beans(exceptEventHandler) are not in the allow list but also not in the deny list; they can be added viadecodeFilterAllowPatternsoraddAllowPatterns. - If you need to block additional packages or classes beyond the built-in deny list, add them via
decodeFilterDenyPatternsoraddDenyPatterns.
File: docs/EN/CreateCache.md
CacheManager
use CacheManager to create Cache instance, it returns same Cache instance with @Cached if area and name equals.
notice: in jetcache 2.7 CreateCache annotation is deprecated, use CacheManager.getOrCreateCache(QuickConfig) instead
example:
@Autowired
private CacheManager cacheManager;
private Cache<String, UserDO> userCache;
@PostConstruct
public void init() {
QuickConfig qc = QuickConfig.newBuilder("userCache")
.expire(Duration.ofSeconds(100))
.cacheType(CacheType.BOTH) // two level cache
.syncLocal(true) // invalidate local cache in all jvm process after update
.build();
userCache = cacheManager.getOrCreateCache(qc);
}CreateCache annotation
You can use @CreateCache annotation to create and configure a Cache instance in a Spring Bean.
For Example:
@CreateCache(expire = 100)
private Cache<Long, UserDO> userCache;The attributes of @CreateCache
| attribute | default value | description |
|---|---|---|
| area | “default” | If you want to use multi backend cache system, you can setup multi "cache area" in configuration, this attribute specifies the name of the "cache area" you want to use. |
| name | undefined | The name of this Cache instance, optional. If you do not specify, JetCache will auto generate one. The name is used to display statistics information and as part of key prefix when using a remote cache. If two @CreateCache have same name and area, they will point to same Cache instance. |
| expire | undefined | The default expire time of this Cache instance. Use global config if the attribute value is absent, and if the global config is not defined either, use infinity. |
| timeUnit | TimeUnit.SECONDS | Specify the time unit of expire |
| cacheType | CacheType.REMOTE | Type of the Cache instance. May be CacheType.REMOTE, CacheType.LOCAL, CacheType.BOTH. Use two level cache (local+remote) when value is CacheType.BOTH. |
| localLimit | undefined | Specify max elements in local memory when cacheType is CacheType.LOCAL or CacheType.BOTH. Use global config if the attribute value is absent, and if the global config is not defined either, use 100. |
| serialPolicy | undefined | Specify the serialization policy of remote cache when cacheType is CacheType.REMOTE or CacheType.BOTH. The JetCache build-in serialPolicy are SerialPolicy.JAVA or SerialPolicy.KRYO. Use global config if the attribute value is absent, and if the global config is not defined either, use SerialPolicy.JAVA. |
| keyConvertor | undefined | Specify the key convertor. Used to convert the complex key object. The JetCache build-in keyConvertor are KeyConvertor.FASTJSON, KeyConvertor.JACKSON, KeyConvertor.JACKSON3 or KeyConvertor.NONE. NONE indicate do not convert, FASTJSON will use fastjson2 to convert key object to a string (since 2.8, fastjson1 is removed). Use global config if the attribute value is absent. |
Default values
There are some attributes in the above table has no default value. JetCache will use global config value when you not specify the value in annotation.
See Configuration details for more information about global config.
File: docs/EN/Embedded.md
The keyConvertor is optional if you are using Cache API in jetcache-core,
the local cache uses equals to identity the key.
You must specify keyConvertor if you use annotations in jetcache-anno, such as @Cached and @CreateCache.
There are two local cache (class AbstractEmbeddedCache) implementation in JetCache.
LinkedHashMapCache
LinkedHashMapCache is a simple implementation in JetCache.
It is built on java.util.LinkedHashMap and supports LRU algorithm.
Cache<Long, OrderDO> cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder()
.limit(100)
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();CaffeineCache
CaffeineCache is built on caffeine cache.
Cache<Long, OrderDO> cache = CaffeineCacheBuilder.createCaffeineCacheBuilder()
.limit(100)
.expireAfterWrite(200, TimeUnit.SECONDS)
.buildCache();File: docs/EN/GettingStarted.md
Create Cache instance
Create a Cache instance using @CreateCache annotation with default TTL 100 seconds.
@Autowired
private CacheManager cacheManager;
private Cache<Long, UserDO> userCache;
@PostConstruct
public void init() {
QuickConfig qc = QuickConfig.newBuilder("userCache") // name used in statistical information
.expire(Duration.ofSeconds(100))
//.cacheType(CacheType.BOTH) // create two level cache
//.localLimit(100) // limit for local cache elements, only used for CacheType.LOCAL and CacheType.BOTH
//.syncLocal(true) // invalidate local cache in other JVM after updates, only used for CacheType.BOTH, need set broadcastChannel in configuration.
.build();
userCache = cacheManager.getOrCreateCache(qc);
}Then use Cache instance like a map:
UserDO user = userCache.get(123L);
userCache.put(123L, user);
userCache.remove(123L);Create method cache
@Cached can be used to add method cache for a method.
JetCache use Spring AOP to generate proxy to support method cache。
The @Cached annotation can be add on interface method or class method, but the interface or class must defined as a Spring bean.
public interface UserService {
@Cached(name="UserService.getUserById", expire = 3600)
User getUserById(long userId);
}Basic configuration (using Spring Boot)
This example using jedis to accessing redis(or you can consider using lettuce client):
POM
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>${jetcache.latest.version}</version>
</dependency>Create a Spring Boot style configuration file application.yml and put it into the resource dir.
jetcache:
statIntervalMinutes: 15
areaInCacheName: false
local:
default:
type: linkedhashmap
keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
remote:
default:
type: redis
keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
broadcastChannel: projectA
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: 127.0.0.1
port: 6379Note: JetCache 2.8.x enables the deserialization security filter by default. The configuration above uses the
javaserializer. If your cached values contain custom classes (e.g.UserDO,OrderDO, etc.), deserialization will be blocked by the filter. You need to adddecodeFilterAllowPatternsto allow your classes:yamljetcache: decodeFilterAllowPatterns: - com.company.mypackage. # allow all classes under this packageIf you also need to block additional packages or classes, configure
decodeFilterDenyPatterns. See the "Deserialization Filter Configuration" section in the configuration docs for details. You can setjetcache.decodeFilterEnabled: falseto disable the filter temporarily (NOT recommended in production).
Then create the application class of Spring Boot:
package com.company.mypackage;
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableMethodCache(basePackages = "com.company.mypackage")
@EnableCreateCacheAnnotation
public class MySpringBootApp {
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class);
}
}The @EnableMethodCache and @EnableCreateCacheAnnotation annotation activate @Cached and @CreateCache respectively.
Other code are same with standard Spring Boot Application. This class can run directly using main method.
Basic configuration (without Spring Boot)
This example using jedis to accessing redis:
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-anno</artifactId>
<version>${jetcache.latest.version}</version>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-redis</artifactId>
<version>${jetcache.latest.version}</version>
</dependency>The following code configure JetCache using hand coding, then you can use @CreateCache and @Cached in you beans.
/* Detailed source-code truncated for AI context efficiency. */read more
- Initiate
Cacheinstance using CacheManager - Basic Cache API
- Method cache using annotation(@Cached, @CacheUpdate, @CacheInvalidate)
- Configuration details
File: docs/EN/MethodCache.md
The method caching in JetCache is similar like Spring Cache. JetCache provide naitve TTL support and two level cache support.
Add @Cached on a method of a Spring bean to enable method caching. Since 2.4 @CacheUpdate and @CacheInvalidate are introduced for removing and updating method cache. You can even add the annotation on the interface that the bean implements.
public interface UserService {
@Cached(name="userCache.", key="#userId", expire = 3600)
User getUserById(long userId);
@CacheUpdate(name="userCache.", key="#user.userId", value="#user")
void updateUser(User user);
@CacheInvalidate(name="userCache.", key="#userId")
void deleteUser(long userId);
}the key and value attribute use SpEL script. To enable use parameter name such as key="#userId", the -parameters javac compiler flag should be set, otherwise use index to access parameters like key="args[0]".
The attributes of @Cached are similar with @CreateCache except @Cached has more attributes:
| attribute | default value | description |
|---|---|---|
| area | “default” | If you want to use multi backend cache system, you can setup multi "cache area" in configuration, this attribute specifies the name of the "cache area" you want to use. |
| name | undefined | The unique name of this Cache instance in an area, optional. If you do not specify, JetCache will auto generate one. The name is used to display statistics information and as part of key prefix when using a remote cache. |
| key | undefined | use SpEL script to specify the key. If not specified, JetCache will auto generate one using all method parameters. |
| expire | undefined | The expire time. Use global config if the attribute value is absent, and if the global config is not defined either, use infinity instead. |
| timeUnit | TimeUnit.SECONDS | Specify the time unit of expire |
| cacheType | CacheType.REMOTE | Type of the Cache instance. May be CacheType.REMOTE, CacheType.LOCAL, CacheType.BOTH. Create a two level cache (local+remote) when value is CacheType.BOTH. |
| localLimit | undefined | Specify max elements in local memory when cacheType is CacheType.LOCAL or CacheType.BOTH. Use global config if the attribute value is absent, and if the global config is not defined either, use 100 instead. |
| localExpire | undefined | Only use with cacheType=CacheType.BOTH, specify a different local expire (typically less than expire) for local cache |
| serialPolicy | undefined | Specify the serialization policy of remote cache when cacheType is CacheType.REMOTE or CacheType.BOTH. The JetCache build-in serialPolicy are SerialPolicy.JAVA or SerialPolicy.KRYO. Use global config if the attribute value is absent, and if the global config is not defined either, use SerialPolicy.JAVA instead. |
| keyConvertor | undefined | Specify the key convertor. Used to convert the complex key object. The JetCache build-in keyConvertor are KeyConvertor.FASTJSON, KeyConvertor.JACKSON, KeyConvertor.JACKSON3 or KeyConvertor.NONE. NONE indicate do not convert, FASTJSON will use fastjson2 to convert key object to a string (since 2.8, fastjson1 is removed). Use global config if the attribute value is absent. |
| enabled | true | Specify whether the method caching is enabled. If set to false, you can enable it in thread context using CacheContext.enableCache(Supplier<T> callback) |
| cacheNullValue | false | Specify whether a null value should be cached. |
| condition | undefined | Expression script used for conditioning the method caching, the cache is not used when evaluation result is false. Can't refer return value of real method. |
| postCondition | undefined | Expression script used for conditioning the method cache updating, the cache updating action is vetoed when the evaluation result is false. Evaluation occurs after real method invocation so we can refer #result in script. |
@CacheInvalidate attribute table:
| attribute | default value | description |
|---|---|---|
| area | “default” | If you want to use multi backend cache system, you can setup multi "cache area" in configuration, this attribute specifies the name of the "cache area" you want to use. |
| name | undefined | The unique name of this Cache instance in an area. refer to name of @Cached. |
| key | undefined | use SpEL script to specify the key. |
| condition | undefined | Expression script used for conditioning the cache operation, the operation is vetoed when evaluation result is false. Evaluation occurs after real method invocation so we can refer #result in script. |
@CacheUpdate attribute table:
| attribute | default value | description |
|---|---|---|
| area | “default” | If you want to use multi backend cache system, you can setup multi "cache area" in configuration, this attribute specifies the name of the "cache area" you want to use. |
| name | undefined | The unique name of this Cache instance in an area. refer to name of @Cached. |
| key | undefined | use SpEL script to specify the key. |
| value | undefined | use SpEL script to specify the value. |
| condition | undefined | Expression script used for conditioning the cache operation, the operation is vetoed when evaluation result is false. Evaluation occurs after real method invocation so we can refer #result in script. |
Note that remote cache operation related to @CacheUpdate and @CacheInvalidate may fail, so it is important to set the '''expire''' attribute.
@CacheRefresh attribute table:
| attribute | default value | description |
|---|---|---|
| refresh | undefined | interval of refreshment |
| timeUnit | TimeUnit.SECONDS | time unit |
| stopRefreshAfterLastAccess | undefined | if specified, refresh action will stop if the associated key is not accessed after specified time unit |
| refreshLockTimeout | 60 seconds | the distributed lock timeout when cacheType is REMOTE or BOTH |
@CachePenetrationProtect:
This annotation used to synchronize concurrent cache loading operation.
Currently it only take effect only in each single JVM, that is, in one JVM there is only one thread load for same key,
other threads wait for the result.
There are some attributes in the above table has no default value. JetCache will use global config when you not specify the value in annotation.
See Configuration details for more information about global config.