Spring Boot Caching Techniques

Loading

Caching is a critical technique for improving the performance of applications by reducing the load on databases and external services. Spring Boot provides robust support for caching through its Spring Cache Abstraction. Below is a detailed guide on Spring Boot Caching Techniques, including configuration, annotations, and best practices.


1. Add Caching Dependency

To enable caching in Spring Boot, add the spring-boot-starter-cache dependency to your pom.xml (for Maven) or build.gradle (for Gradle).

Maven:

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

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-cache'

2. Enable Caching

Enable caching in your Spring Boot application by adding the @EnableCaching annotation to your main application class or a configuration class.

Example:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCaching
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

3. Configure Cache Provider

Spring Boot supports multiple caching providers, such as:

  • In-Memory Cache: Simple, default option (e.g., ConcurrentHashMap).
  • Ehcache: A widely used Java cache.
  • Caffeine: A high-performance Java caching library.
  • Redis: A distributed in-memory data store.

a. In-Memory Cache (Default)

No additional configuration is required for the default in-memory cache.

b. Ehcache

Add the Ehcache dependency and configure it.

Maven:
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
Configuration (ehcache.xml):
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://www.ehcache.org/ehcache.xsd">
    <cache alias="myCache">
        <heap unit="entries">1000</heap>
    </cache>
</config>
Enable in application.properties:
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:ehcache.xml

c. Caffeine

Add the Caffeine dependency.

Maven:
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>
Configuration:
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager("myCache");
        cacheManager.setCaffeine(Caffeine.newBuilder()
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(100));
        return cacheManager;
    }
}

d. Redis

Add the Redis dependency and configure it.

Maven:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Configuration (application.properties):
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379

4. Caching Annotations

Spring Boot provides several annotations to manage caching.

a. @Cacheable

Caches the result of a method.

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class ProductService {

    @Cacheable("products")
    public Product getProductById(Long id) {
        // Simulate a slow operation
        simulateSlowService();
        return new Product(id, "Product " + id);
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

b. @CachePut

Updates the cache with the result of a method.

@CachePut(value = "products", key = "#product.id")
public Product updateProduct(Product product) {
    // Update product in the database
    return product;
}

c. @CacheEvict

Removes an entry from the cache.

@CacheEvict(value = "products", key = "#id")
public void deleteProduct(Long id) {
    // Delete product from the database
}

d. @Caching

Combines multiple caching operations.

@Caching(
    evict = {
        @CacheEvict(value = "products", key = "#id"),
        @CacheEvict(value = "allProducts", allEntries = true)
    }
)
public void deleteProduct(Long id) {
    // Delete product from the database
}

e. @CacheConfig

Specifies common cache configurations for a class.

@Service
@CacheConfig(cacheNames = "products")
public class ProductService {
    // Methods will use the "products" cache by default
}

5. Conditional Caching

You can conditionally cache results using the condition and unless attributes.

Example:

@Cacheable(value = "products", condition = "#id > 10", unless = "#result.price > 100")
public Product getProductById(Long id) {
    // Fetch product
}

6. Custom Key Generation

Customize cache keys using the key attribute or a custom key generator.

Example:

@Cacheable(value = "products", key = "#id + '_' + #name")
public Product getProductByIdAndName(Long id, String name) {
    // Fetch product
}

Custom Key Generator:

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component("customKeyGenerator")
public class CustomKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        return method.getName() + "_" + params[0];
    }
}

Usage:

@Cacheable(value = "products", keyGenerator = "customKeyGenerator")
public Product getProductById(Long id) {
    // Fetch product
}

7. Cache Expiration and Eviction

Configure cache expiration and eviction policies based on your caching provider.

Example for Caffeine:

Caffeine.newBuilder()
    .expireAfterWrite(10, TimeUnit.MINUTES) // Expire after 10 minutes
    .maximumSize(100) // Maximum of 100 entries
    .build();

8. Monitoring Cache

Use Spring Boot Actuator to monitor cache metrics.

Add Actuator Dependency:

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

Enable Cache Metrics:

management.endpoints.web.exposure.include=*
management.metrics.enable.cache=true

Access cache metrics at /actuator/metrics/cache.requests.


9. Best Practices

  • Use Meaningful Cache Names: Name caches based on their purpose.
  • Limit Cache Size: Avoid memory issues by setting size limits.
  • Set Expiration Policies: Prevent stale data by setting TTL (Time-To-Live).
  • Monitor Cache Performance: Use Actuator to track cache usage and hit rates.
  • Evict Stale Data: Use @CacheEvict to remove outdated entries.

By leveraging Spring Boot’s caching capabilities, you can significantly improve the performance and scalability of your application. Let me know if you need further assistance!

Leave a Reply

Your email address will not be published. Required fields are marked *