DEV Community

Nikhil Soman Sahu
Nikhil Soman Sahu

Posted on

Spring Boot Caching Simplified: How to Use JetCache Effectively

Caching is a powerful technique that can drastically improve application performance by reducing the need to retrieve data from a slow data store like a database. JetCache is a Java-based caching library that integrates seamlessly with Spring Boot, providing annotations, easy configuration, and multi-level caching support (local + remote). In this article, we will explore how to use JetCache in a Spring Boot application, covering its key features and practical examples.

Why JetCache?

JetCache stands out for the following reasons:

  • Ease of Use: It provides simple annotations like @Cached for caching methods.
  • Support for Multi-Level Caching: You can configure both local (in-memory) and remote (Redis) caches easily.
  • Auto Configuration with Spring Boot: JetCache integrates easily with Spring Boot's auto-configuration features.
  • Out-of-the-Box Integration: It supports various cache providers such as Redis, Caffeine, and even custom implementations.

Key Features of JetCache

  • Declarative Caching: Use annotations like @Cached, @CacheInvalidate, and @CacheUpdate for caching behavior.
  • Multi-Level Cache: It allows using both local and remote cache providers for efficient caching strategies.
  • Support for Key Generation: JetCache provides automatic or custom key generation for cache entries.
  • TTL (Time to Live) Settings: Set expiration time for cache entries on both local and remote levels.

Let’s now dive into how to integrate JetCache into a Spring Boot application.

Step 1: Set Up the Spring Boot Project

To get started, create a new Spring Boot project with the necessary dependencies. You can use Spring Initializr or manually add the following dependencies to your pom.xml:

<dependency>
    <groupId>com.github.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis-lettuce</artifactId> <!-- For Redis support -->
    <version>2.7.14</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId> <!-- For Local Cache -->
</dependency>
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure JetCache in application.yml

spring:
  cache:
    type: none

jetcache:
  statIntervalMinutes: 5  # Statistics output interval
  areaInCacheName: false
  local:
    default:
      limit: 100  # Maximum number of entries in local cache
      expireAfterWriteInMillis: 60000  # TTL for local cache
  remote:
    default:
      type: redis
      keyConvertor: fastjson
      ttlInMillis: 300000  # 5 minutes TTL for Redis cache
      jedis:
        host: localhost
        port: 6379
        password: ""  # Add password if Redis requires authentication
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a Service with Caching Enabled

Let’s create a simple service that fetches user data, simulating a database query, and cache the result.

User Entity

public class User {
    private Long id;
    private String name;

    // Constructor, Getters, and Setters
    public User(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters and setters
}
Enter fullscreen mode Exit fullscreen mode

UserService

import com.alicp.jetcache.anno.Cached;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    // Simulate a database call
    @Cached(name = "userCache-", key = "#id", expire = 300, localExpire = 60)
    public User getUserById(Long id) {
        simulateSlowService();
        return new User(id, "User " + id);
    }

    // Invalidate the cache entry for the given ID
    @CacheInvalidate(name = "userCache-", key = "#id")
    public void invalidateUserCache(Long id) {
        // This method will remove the user from the cache
    }

    // Simulate a slow response (e.g., a database call)
    private void simulateSlowService() {
        try {
            Thread.sleep(3000);  // Simulate delay
        } catch (InterruptedException e) {
            throw new IllegalStateException(e);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In this service:

  • The @Cached annotation is used to cache the result of getUserById. The key for the cache is the id, and the cache entry will expire after 5 minutes in Redis and 1 minute in local memory.
  • The @CacheInvalidate annotation allows us to remove a specific entry from the cache.

Step 4: Use the Service in a Controller

Let’s expose this service via a REST controller to fetch and invalidate cached user data.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @GetMapping("/user/{id}/invalidate")
    public String invalidateCache(@PathVariable Long id) {
        userService.invalidateUserCache(id);
        return "Cache for User ID " + id + " invalidated.";
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Test the Caching Behavior

When you run the application, access the following endpoints:

  • GET /user/1: The first call will simulate a slow service and take 3 seconds to return. The result will be cached.
  • GET /user/1 (subsequent call): This call will return the cached result instantly from the local cache (if within 1 minute) or from Redis (if within 5 minutes).
  • GET /user/1/invalidate: This endpoint invalidates the cached data for the user with ID 1.

Step 6: Monitor the Cache

JetCache provides built-in statistics to monitor cache hits and misses. By default, it logs cache statistics every 5 minutes. You can configure this interval or manually output statistics using CacheMonitor.

JetCache Annotations

Let’s dive deeper into some of the key JetCache annotations:

  • @Cached: Caches the result of a method. Parameters:

    • name: Prefix for cache key names.
    • key: SpEL expression to specify cache keys.
    • expire: TTL for remote cache in seconds.
    • localExpire: TTL for local cache in seconds.
  • @CacheInvalidate: Removes an entry from the cache. Parameters:

    • name: Prefix for the cache key name.
    • key: SpEL expression to specify the cache key to invalidate.
  • @CacheUpdate: Updates an existing cache entry. You can use this for methods that modify data and should refresh the cache.

Multi-Level Caching with JetCache

JetCache supports both local and remote caches. Here’s a quick summary of how multi-level caching works:

  • Local Cache: Stored in memory (e.g., using Caffeine). Local cache is typically faster but has limited size.
  • Remote Cache: Stored in external services like Redis. Remote caches are slower but can store much larger datasets.

JetCache uses local cache first. If a cache miss occurs, it will check the remote cache (e.g., Redis). This setup offers a good balance between speed and capacity.

Best Practices for Using JetCache

  1. Avoid Over-Caching: Cache only data that is expensive to retrieve and doesn’t change frequently.
  2. Set Reasonable Expirations: Choose appropriate TTLs for both local and remote caches to avoid stale data.
  3. Monitor Cache Usage: JetCache provides statistics to help you monitor cache performance. Use them to optimize your cache settings.
  4. Consider Cache Size: Especially for local caches, ensure you have limits in place to avoid memory overflow.

Conclusion

JetCache provides a simple yet powerful way to integrate caching into your Spring Boot application. With easy-to-use annotations, support for multi-level caching, and robust integration with popular cache providers like Redis, JetCache can significantly improve your application's performance.

By following the steps in this guide, you can set up caching in your Spring Boot applications quickly and efficiently. Whether you’re caching small lookups in local memory or large datasets in Redis, JetCache has you covered.


Further Reading:

Top comments (0)