## File: docs/EN/AdvancedCacheAPI.md # CacheBuilder The ```CacheBuilder``` provide a way to construct ```Cache``` instance use your own code, See [Here](Builder.md). ```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: ```java 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: ```java CompletionStage 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 : ```java Cache 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: 1. uppercase method such as GET and GET_ALL only operate with cache and do not invoke the loader. 1. loader should be install on ```MultiLevelCache``` if 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: ```java @CreateCache private Cache 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: ```java RefreshPolicy policy = RefreshPolicy.newPolicy(1, TimeUnit.MINUTES) .stopRefreshAfterLastAccess(30, TimeUnit.MINUTES); Cache 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```: ```java @CreateCache private Cache 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: ```java Cache cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder() .limit(100) .expireAfterWrite(200, TimeUnit.SECONDS) .buildCache(); ``` Create ```RedisCache``` (using jedis): ```java GenericObjectPoolConfig pc = new GenericObjectPoolConfig(); pc.setMinIdle(2); pc.setMaxIdle(10); pc.setMaxTotal(10); JedisPool pool = new JedisPool(pc, "localhost", 6379); Cache 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. `OrderDO` above), you need to configure the filter allow list before creating the cache, otherwise deserialization will fail: > ```java > DecodeFilter.getDefault().addAllowPatterns("com.yourcompany."); > ``` > See the "Deserialization Filter Configuration" section in the [configuration docs](Config.md) for details. # Multi level cache ```java Cache multiLevelCache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder() .addCache(memoryCache, redisCache) .expireAfterWrite(100, TimeUnit.SECONDS) .buildCache(); ``` You can even build cache more than two level. # Monitor ```java Cache orderCache = ... CacheMonitor orderCacheMonitor = new DefaultCacheMonitor("OrderCache"); orderCache.config().getMonitors().add(orderCacheMonitor); // jetcache 2.2+, or call builder.addMonitor() before buildCache() // Cache 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](Stat)). 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: ```java public DefaultCacheMonitorManager(int resetTime, TimeUnit resetTimeUnit, Consumer 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: 1. We want that the API of JetCache are more simpler and easy to use than JSR107. 1. Some operation defined in ```javax.cache.Cache``` are difficult to implement efficiently in some specific distributed cache system (eg. some atomic operation and ```removeAll()```). 1. 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. ```java 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 unwrap(Class clazz); Map getAll(Set keys); void putAll(Map map); void removeAll(Set keys); ``` # JetCache Cache API ```java V computeIfAbsent(K key, Function loader) V computeIfAbsent(K key, Function loader, boolean cacheNullWhenLoaderReturnNull) V computeIfAbsent(K key, Function 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. ```java void put(K key, V value, long expire, TimeUnit timeUnit) ``` The put opperation. ```expire``` and ```timeUnit``` specifies the TTL (will overrides defaults). ```java 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: ```java // 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)```: ```java 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: ```java CacheGetResult GET(K key); MultiGetResult GET_ALL(Set keys); CacheResult PUT(K key, V value); CacheResult PUT(K key, V value, long expireAfterWrite, TimeUnit timeUnit); CacheResult PUT_ALL(Map map); CacheResult PUT_ALL(Map map, long expireAfterWrite, TimeUnit timeUnit); CacheResult REMOVE(K key); CacheResult REMOVE_ALL(Set 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: ```java CacheGetResult 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 * `areaInCacheName` default value is now `false` (was `true` in versions prior to 2.8.0). * kryo4 is no longer supported, `com.esotericsoftware:kryo` is upgraded to 5.x. The `KRYO` constant in `SerialPolicy` now uses kryo5 implementation internally. kryo4 serialized data is not compatible with kryo5, wait for old cache entries to expire or clear cache before upgrading * Removed fastjson1 support, `fastjson` key convertor now uses fastjson2 internally. If you need fastjson1, add the dependency yourself and implement a custom KeyConvertor * Removed Spring XML namespace support (`` 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 `decodeFilterAllowPatterns` configuration **at the same time** as upgrading JetCache, including the package names of your custom classes in the allow list. For example: ```yaml jetcache: decodeFilterAllowPatterns: - com.yourcompany. ``` Option 2: Disable the filter during upgrade (same behavior as 2.7): ```yaml jetcache: decodeFilterEnabled: false ``` See the "Deserialization Filter Configuration" section in the [configuration docs](Config.md) 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: 1. if a method like ```put``` in ```Cache``` interface sets expire, then use it. 1. if not set in method like ```put```, use default expire of the ```Cache``` instance 1. the default expire of the ```Cache``` instance can be set in attribute on ```@CreateCache``` or ```@Cached```, if not, JetCache use global config ```defaultExpireInMillis``` defined in yml(for instance ```@Cached(cacheType=local)``` use ```jetcache.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: ```yaml 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 class ``` **Filter 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.` matches `com.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.example` matches `com.example.Foo` but not `com.example.sub.Bar`. The default allow list uses this mode for `java.lang` and `java.net`. - **Exact match** (full class name): matches only one specific class. For example, `org.myapp.dto.UserDTO` matches only `org.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): ```java 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 like `java.io`, `java.beans` (except `EventHandler`) are not in the allow list but also not in the deny list; they can be added via `decodeFilterAllowPatterns` or `addAllowPatterns`. - If you need to block additional packages or classes beyond the built-in deny list, add them via `decodeFilterDenyPatterns` or `addDenyPatterns`. --- ## 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: ```java @Autowired private CacheManager cacheManager; private Cache 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: ```java @CreateCache(expire = 100) private Cache 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](Config.md) 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. ```java Cache cache = LinkedHashMapCacheBuilder.createLinkedHashMapCacheBuilder() .limit(100) .expireAfterWrite(200, TimeUnit.SECONDS) .buildCache(); ``` # CaffeineCache CaffeineCache is built on [caffeine cache](https://github.com/ben-manes/caffeine). ```java Cache 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. ```java @Autowired private CacheManager cacheManager; private Cache 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: ```java 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. ```java 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](RedisWithLettuce.md) client): # POM ```xml com.alicp.jetcache jetcache-starter-redis ${jetcache.latest.version} ``` 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: 6379 ``` > **Note**: JetCache 2.8.x enables the deserialization security filter by default. The configuration above uses the `java` serializer. If your cached values contain custom classes (e.g. `UserDO`, `OrderDO`, etc.), deserialization will be blocked by the filter. You need to add `decodeFilterAllowPatterns` to allow your classes: > ```yaml > jetcache: > decodeFilterAllowPatterns: > - com.company.mypackage. # allow all classes under this package > ``` > If you also need to block additional packages or classes, configure `decodeFilterDenyPatterns`. See the "Deserialization Filter Configuration" section in the [configuration docs](Config.md) for details. You can set `jetcache.decodeFilterEnabled: false` to disable the filter temporarily (**NOT recommended in production**). Then create the application class of Spring Boot: ```java 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: ```xml com.alicp.jetcache jetcache-anno ${jetcache.latest.version} com.alicp.jetcache jetcache-redis ${jetcache.latest.version} ``` 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 ```Cache``` instance using CacheManager](CreateCache.md) * [Basic Cache API](CacheAPI.md) * [Method cache using annotation(@Cached, @CacheUpdate, @CacheInvalidate)](MethodCache.md) * [Configuration details](Config.md) --- ## 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. ```java 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](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html) 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](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html) 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 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](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html) 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](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html) script to specify the key.| |value|undefined|use [SpEL](https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html) 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](Config.md) for more information about global config.