Abstract: JetCache is an open source generic Cache access framework developed by Alibaba. If you are familiar with Spring Cache, please spend some time learning about JetCache. JetCache provides annotated caching similar to Spring Cache, supports TTL, multi-level caching, distributed automatic refresh, and provides a Cache API similar to JSR107 specification.


JetCache is a general-purpose Cache access framework developed by Alibaba. If you are familiar with Spring Cache, take a moment to learn about JetCache.


JetCache’s core capabilities include:
  • Provides a unified, JSR-107-style API to access the Cache and create and configure Cache instances through annotations
  • Declarative method caching with annotations, support for TTL and two-level caching
  • Distributed cache automatic refresh, distributed lock (2.2+)
  • Support for asynchronous Cache apis
  • Spring Boot support
  • The Key generation strategy and the Value serialization strategy can be customized
  • Automatic statistics for all Cache instance and method caches


Looking directly at the code, the simplest usage scenario looks like this:


public interface UserService { @Cached(expire = 3600, cacheType = CacheType.REMOTE) User getUserById(long userId); }


This is similar to Spring Cache, except that the @cached annotation natively supports TTL (timeout). CacheType can be LOCAL, REMOTE, or BOTH.


They respectively represent LOCAL memory, remote Cache Server (such as Redis), and two-level Cache. The appropriate use of LOCAL or BOTH can reduce the pressure of Cache Server and the response time of the service we provide.
Here’s a more complicated example:


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); }


In the first example, we didn’t specify a key. JetCache automatically generates the key based on the parameter. In this example, we specify the key and show the cache update and deletion.


Auto-refresh is JetCache’s killer:


public interface SummaryService{ @Cached(expire = 3600, cacheType = CacheType.REMOTE) @CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS) BigDecimal salesVolumeSummary(int timeId, long catagoryId); }


When cacheType is REMOTE or BOTH, the refresh behavior is globally unique, meaning that even if the application server is in a cluster, multiple servers are not refreshing a key at the same time.


A refresh key task, the first is the key to access after initialization, if the key is not being accessed, for a long time after the time specified in the stopRefreshAfterLastAccess, related to refresh the task will be automatically removed, thus avoiding the waste of resources to make no sense to refresh.


Annotations added to methods don’t provide the most flexible control after all, so JetCache provides a Cache API that works like Map:


UserDO user = userCache.get(12345L); userCache.put(12345L, loadUserFromDataBase(12345L)); userCache.remove(12345L); userCache.computeIfAbsent(1234567L, (key) -> loadUserFromDataBase(1234567L));


In fact, the Cache API implements some of the methods of the Cache interface of the JSR107 specification, and may be fully implemented in larger versions in the future.
Cache instances can be created with annotations:


@CreateCache(expire = 100, cacheType = CacheType.BOTH, localLimit = 50) private Cache<Long, UserDO> userCache;


It can also be created using a builder similar to Guava Cache/Caffeine:


GenericObjectPoolConfig pc = new GenericObjectPoolConfig(); pc.setMinIdle(2); pc.setMaxIdle(10); pc.setMaxTotal(10); JedisPool pool = new JedisPool(pc, “localhost”, 6379); Cache<Long, UserDO> userCache = RedisCacheBuilder.createRedisCacheBuilder() .keyConvertor(FastjsonKeyConvertor.INSTANCE) .valueEncoder(JavaValueEncoder.INSTANCE) .valueDecoder(JavaValueDecoder.INSTANCE) .jedisPool(pool) .keyPrefix(“userCache-“) .expireAfterWrite(200, TimeUnit.SECONDS) .buildCache();


Cache interfaces support asynchrony:
CacheGetResult r = cache.GET(userId); CompletionStage

future = r.future(); future.thenRun(() -> { if(r.isSuccess()){ System.out.println(r.getValue()); }});


It is possible to implement distributed locks that are not strict:
cache.tryLockAndRun(“key”, 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());


You can also use the Cache API to automatically refresh:
@CreateCache @CacheRefresh(timeUnit = TimeUnit.MINUTES, refresh = 60) private Cache<String, Long> orderSumCache; @PostConstruct public void init(){ orderSumCache.config().setLoader(this::loadOrderSumFromDatabase); }


If you don’t use annotations, you can do auto-refresh with Builder as well:
Cache

orderSumCache = RedisCacheBuilder.createRedisCacheBuilder() …… Omit. RefreshPolicy (refreshPolicy. NewPolicy (60, TimeUnit. SECONDS)). The loader (this: : loadOrderSumFromDatabase). BuildCache ();
,>


Currently supported caching systems include the following four, and it is easy to support a new type of cache:
  • Caffeine (Local Memory)
  • LinkedHashMap (a simple LRU cache implemented by JetCache itself, based on local memory)
  • Alibaba Tair (related implementation is not open source on Github, can be found on Alibaba internal Gitlab)
  • Redis


System requirements for using JetCache:
  • JDK: Java 8 is required
  • Spring Framework: above 4.0.8, not required if you do not use annotations
  • Spring Boot: 1.1.9 + (optional)


Additional documentation can be found on the Github wiki.


The original link
To read more articles, please scan the following QR code: