Master Spring Cache Annotations: @EnableCaching, @Cacheable, @CachePut, @CacheEvict Explained

This article explains how Spring's caching annotations—@EnableCaching, @Cacheable, @CachePut, and @CacheEvict—work together to simplify cache management, includes Maven dependency setup, configuration class, entity and service code, a full Spring Boot example, test cases, and visual illustrations of cache miss, hit, update, and eviction.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Master Spring Cache Annotations: @EnableCaching, @Cacheable, @CachePut, @CacheEvict Explained

Background

Cache is a common technique to reduce database read pressure and improve query performance. It is used for data that changes infrequently but is accessed frequently, such as configuration, product, or user information. Typical usage reads from DB once, stores in cache with TTL, and synchronizes on updates or deletes.

Instead of writing custom cache annotations, Spring already provides powerful cache annotation support.

Spring Cache Annotations

Key annotations:

@EnableCaching : Enables cache support; must be placed on a configuration class.

@Cacheable : Marks a method or class as cacheable; caches the method result. Attributes: value / cacheNames (cache name), key (SpEL key), condition (SpEL condition).

@CachePut : Executes the method and updates the cache with the result; used for cache synchronization.

@CacheEvict : Removes entries from the cache, typically on delete operations.

Engineering Practice

3.1 Add Dependency

Include spring-boot-starter-data-redis in the Maven pom.

<project>
  <modelVersion>4.0.0</modelVersion>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>${spring.boot.version}</version>
    </dependency>
    ...
  </dependencies>
</project>

3.2 Core Code

Cache configuration class:

package com.java.demo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import java.time.Duration;

@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Value("${cache.enable:false}")
    private Boolean cacheEnable;

    @Value("${cache.ttl:120}")
    private Long cacheTtl;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        if (cacheEnable) {
            RedisCacheConfiguration config = instanceConfig();
            return RedisCacheManager.builder(redisConnectionFactory)
                    .cacheDefaults(config)
                    .transactionAware()
                    .build();
        }
        return new NoOpCacheManager();
    }

    private RedisCacheConfiguration instanceConfig() {
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(cacheTtl))
                .disableCachingNullValues();
    }
}

Entity class:

public class User implements Serializable {
    private String userId;
    private String userName;
    // getters, setters, toString
}

Service interface and implementation with cache annotations:

public interface UserService {
    User getUserById(String userId);
    User updateUser(User user);
    void deleteUser(String userId);
}
@Component
public class UserServiceImpl implements UserService {

    @Cacheable(cacheNames = "users", key = "#userId")
    public User getUserById(String userId) { /* ... */ }

    @CachePut(cacheNames = "users", key = "#user.userId")
    public User updateUser(User user) { return user; }

    @CacheEvict(cacheNames = "users", key = "#userId")
    public void deleteUser(String userId) { /* ... */ }
}

Application entry point:

@SpringBootApplication
@ComponentScan("com.java.demo")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}

Cache related properties (spring.redis.* and custom cache.enable/ttl) are set in application.properties.

3.3 Test Cases

JUnit test demonstrates first read (cache miss), second read (cache hit), update (CachePut), and delete (CacheEvict).

public class CacheTest {
    @Autowired
    private UserService userService;

    @Test
    public void testCache() {
        logger.info("1.user:{}", userService.getUserById("123"));
        logger.info("2.user:{}", userService.getUserById("123"));
        userService.updateUser(new User("123","zhang hua"));
        logger.info("3.user:{}", userService.getUserById("123"));
        userService.deleteUser("123");
        logger.info("test finish!");
    }
}

Images illustrate cache miss, hit, update, and eviction processes.

Cache miss
Cache miss
Cache hit
Cache hit
Cache update
Cache update
Cache eviction
Cache eviction

Conclusion

Using Spring's @EnableCaching and related annotations decouples cache logic from business code, making it cleaner and more efficient. However, @EnableCaching does not expose a cache TTL attribute; TTL must be configured via CacheManager.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendcacheRedisspringAnnotations
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.