jetcache is a free, open source databases project written in Java and released under Apache-2.0. It has 5,613 GitHub stars, 1,085 forks and 428 open issues, and was last pushed 27 days ago. On this registry it ranks #110 of 143 tracked projects in Databases, with 5 head-to-head comparisons available.

What is jetcache?

JetCache is an Apache-2.0 Java cache abstraction from Alibaba that gives one uniform Cache API and richer annotations than Spring Cache across Redis, Tair, Caffeine, and in-memory caches.

What it is

JetCache is a cache abstraction layer for Java. It sits between application code and the underlying cache products, exposing a single Cache interface plus a set of declarative annotations, so the same method does not need to be rewritten when the storage behind it changes. Four implementations ship with it: RedisCache, TairCache (which is not open source on GitHub), CaffeineCache for in-memory use, and a simple LinkedHashMapCache, also in-memory. Instances are created and configured through a CacheManager, either by hand or with QuickConfig.

The concrete problem it solves is the gap left by Spring Cache. Spring's annotations do not carry native TTL, do not support two-level caching, and do not handle refresh in a distributed environment. JetCache does all three. A @Cached method can carry expire = 3600 in seconds, and cacheType = CacheType.BOTH builds a two-level cache that pairs a local in-memory layer with a remote one, with the local layer bounded by something like localLimit(50) on an LRU basis. Invalidation of local copies across every JVM process after an update arrives in version 2.7 and later.

Key capabilities

  • Declarative method caching through @Cached, @CacheUpdate, and @CacheInvalidate, with expire for TTL and keys written in SpEL such as key="#userId" — which needs the -parameters javac flag, or key="args[0]" if that flag is unavailable.
  • Two-level caching via cacheType = CacheType.BOTH, combining a local in-memory cache with a remote system such as Redis.
  • Auto refresh with @CacheRefresh, configured by refresh, stopRefreshAfterLastAccess, and timeUnit, plus @CachePenetrationProtect to load the cache synchronously under multi-threaded access.
  • Uniform programmatic access through Cache and CacheManager, including getOrCreateCache(qc) and QuickConfig.newBuilder(...), with statistics collected at both the Cache instance level and the method level.
  • Pluggable key generation and value serialization: key convertors for fastjson2, jackson, and jackson3, and value encoders/decoders for java, kryo, and kryo5.
  • Distributed cache auto refresh and distributed lock, available from 2.2 onward.
  • Asynchronous access through the Cache API from 2.2 onward, using the Redis lettuce client, and local cache invalidation across all JVM processes after an update from 2.7 onward.

Who uses it and how

  • Java services already running Spring Boot, which JetCache supports directly, that need TTL and refresh semantics Spring Cache does not provide.
  • Systems deployed across multiple JVM instances, where the 2.7+ cross-process local cache invalidation and the distributed lock keep local copies from going stale after a write.
  • Read-heavy workloads that benefit from CacheType.BOTH, keeping a small bounded local working set (for example a localLimit of 50 entries) in front of a remote Redis tier.
  • Teams that need to change cache backend without touching business code, since the Cache abstraction covers Redis, Tair, Caffeine, and LinkedHashMapCache.
  • Applications that already depend on fastjson2, Jackson, or Kryo and want to reuse those libraries for cache keys and values rather than introducing another serializer.

Getting started

Use the library as a Maven dependency — the project builds its own CI with Maven — and then either declare @Cached on a method or autowire a CacheManager and build an instance with QuickConfig. Spring Boot support and annotation support are optional; the current line requires JDK17+, Spring Framework 6.x+, and Spring Boot 3.x+, while JDK8+ users are held to 2.7 and earlier.

How it compares

Among the tools named in the facts, JetCache occupies the layer above Caffeine, Redis, and Tair rather than competing with them: Caffeine and LinkedHashMapCache serve as the in-memory implementations and Redis and Tair as the remote ones, so a project can adopt JetCache without dropping an existing cache product. Its closest point of comparison is Spring Cache, whose annotation model it deliberately extends with native TTL, two-level caching, and distributed refresh, and the jcache topic places it in the same space as the JSR-107 API.

When to use it — and when not to

A self-hoster taking on the Redis-backed path must run and operate that Redis deployment, and anyone using TairCache depends on a component that is not open source on GitHub. Projects staying on JDK8 or older Spring versions cannot use the current 2.8+ line and must remain on 2.7 or earlier, and the 428 open issues are worth reviewing before adopting it for a system where cache correctness is critical. Teams with no distributed cache tier and no need for TTL or refresh are better served by plain Spring Cache or Caffeine alone.

project readme (upstream, from github) — read inline

Java CI with Maven Coverage Status GitHub release License

Introduction

JetCache is a Java cache abstraction which provides uniform usage for different caching solutions. It provides more powerful annotations than those in Spring Cache. The annotations in JetCache supports native TTL, two level caching, and automatically refresh in distrubuted environments, also you can manipulate Cache instance by your code. Currently, there are four implementations: RedisCache, TairCache(not open source on github), CaffeineCache (in memory) and a simple LinkedHashMapCache (in memory). Full features of JetCache:

  • Manipulate cache through uniform Cache API.
  • Declarative method caching using annotations with TTL(Time To Live) and two level caching support
  • Create & configure Cache instance with cache manager
  • Automatically collect access statistics for Cache instance and method level cache
  • The strategy of key generation and value serialization can be customized
  • Cache key convertor supported: fastjson2/jackson/jackson3; Value encoder/decoder supported: java/kryo/kryo5
  • Distributed cache auto refresh and distributed lock. (2.2+)
  • Asynchronous access using Cache API (2.2+, with redis lettuce client)
  • Invalidate local caches (in all JVM process) after updates (2.7+)
  • Spring Boot support

requirements:

  • JDK17+ (jetcache 2.8+); JDK8+ (jetcache 2.7 and earlier)
  • Spring Framework6.x+ (optional, with annotation support)
  • Spring Boot3.x+ (optional)

Visit docs for more details.

Getting started

Method cache

Declare method cache using @Cached annotation.

expire = 3600 indicates that the elements will expire in 3600 seconds after being set. JetCache automatically generates the cache key with all the parameters.

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

Using key attribute to specify cache key using SpEL script.

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 order to 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]"

Auto refreshment:

public interface SummaryService{
    @Cached(expire = 3600, cacheType = CacheType.REMOTE)
    @CacheRefresh(refresh = 1800, stopRefreshAfterLastAccess = 3600, timeUnit = TimeUnit.SECONDS)
    @CachePenetrationProtect
    BigDecimal summaryOfToday(long categoryId);
}

CachePenetrationProtect annotation indicates that the cache will be loaded synchronously in multi-thread environment.

Cache API

Create a Cache instance with CacheManager:

@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
        .localLimit(50)
        .syncLocal(true) // invalidate local cache in all jvm process after update
        .build();
    userCache = cacheManager.getOrCreateCache(qc);
}

The code above create a Cache instance. cacheType = CacheType.BOTH define a two level cache (a local in-memory-cache and a remote cache system) with local elements limited upper to 50(LRU based evict). You can use it like a map:

UserDO user = userCache.get(12345L);
userCache.put(12345L, loadUserFromDataBase(12345L));
userCache.remove(12345L);

userCache.computeIfAbsent(1234567L, (key) -> loadUserFromDataBase(1234567L));

Advanced API

Asynchronous API:

CacheGetResult r = cache.GET(userId);
CompletionStage<ResultData> future = r.future();
future.thenRun(() -> {
    if(r.isSuccess()){
        System.out.println(r.getValue());
    }
});

Distributed lock:

cache.tryLockAndRun("key", 60, TimeUnit.SECONDS, () -> heavyDatabaseOperation());

Read through and auto refresh:

@Autowired
private CacheManager cacheManager;
private Cache<String, Long> orderSumCache;

@PostConstruct
public void init() {
    QuickConfig qc = QuickConfig.newBuilder("userCache")
        .expire(Duration.ofSeconds(3600))
        .loader(this::loadOrderSumFromDatabase)
        .refreshPolicy(RefreshPolicy.newPolicy(60, TimeUnit.SECONDS).stopRefreshAfterLastAccess(100, TimeUnit.SECONDS))
        .penetrationProtect(true)
        .build();
    orderSumCache = cacheManager.getOrCreateCache(qc);
}

Configuration with Spring Boot

pom:

<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>${jetcache.latest.version}</version>
</dependency>

App class:

@SpringBootApplication
@EnableMethodCache(basePackages = "com.company.mypackage")
@EnableCreateCacheAnnotation // deprecated in jetcache 2.7, can be removed if @CreateCache is not used
public class MySpringBootApp {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApp.class);
    }
}

spring boot application.yml config:

jetcache:
  statIntervalMinutes: 15
  areaInCacheName: false
  decodeFilterAllowPatterns:
    - com.yourcompany. #add your package here, or set decodeFilterEnabled: false to disable the filter
  local:
    default:
      type: linkedhashmap #other choose:caffeine
      keyConvertor: fastjson2 #other choose:fastjson(same as fastjson2)/jackson/jackson3
      limit: 100
  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}

Visit detail configuration for more instructions

More docs

Visit docs for more details.

For upgrade see changelog and compatibility notes.

Frequently asked questions

Is jetcache free to use?

jetcache is open source under the Apache-2.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does jetcache do?

JetCache is a Java cache framework.

What is jetcache written in?

jetcache is primarily written in Java. Its source is publicly available at https://github.com/alibaba/jetcache, and it has 5,613 GitHub stars.