Caching Data with Spring

Gyeongsun (Sunny) Park
DevOps.dev
Published in
3 min readAug 14, 2022

--

What is Cache?

The Cache frequently uses data storage that can be accessed at high speed. If any requests to data is configured to enable caching, data can be accessed faster than it would be by accessing the original storage because caching data is purposely stored in a space for quick access. Data that is sought or calculated before is able to be reused efficiently by caching.

The Spring Framework provides support for adding cache with minimal impact on code. The reason why this is possible is that the Spring Framework provides the caching abstraction, not caching implementation.

The caching abstraction in Spring Framework can add to the method transparently using AOP’s structural feature when running the method. Because of AOP, the Cache in Spring Framework can be applied to various implementations of that abstraction; for example, JDK java.util.concurrent.ConcurrentMap based caches, Ehcache 2.xx, Gemfire Cache, Caffeine, and JSR-107 compliant caches.

In other words, we can add or modify caching easily to the method without applying cache API and codes. When the application environment or type of applied cache changes(e.g. application version, deprecated methods), the application code is not impacted significantly due to the caching abstraction.

To use caching in Spring Framework, you have to configure the CacheManager first. Let’s see what kind of CacheManager there is.

📌 Cache Manager

🔗 official docs link

The caching abstraction should register the CacheManager supported to enable caching to the Bean.

✔️ SimpleCacheManager

Simple CacheManager working against a given collection of caches. This can be useful for testing or simple caching declarations.

@Bean 
public CacheManager cacheManager() {
Cache cache = new ConcurrentMapCache("byUsername");
SimpleCacheManager manager = new SimpleCacheManager();
manager.setCaches(Arrays.asList(cache));
return manager;
}

✔️ ConcurrentMapCacheManager

The ConcurrentMapCacheManager is using ConcurrentHashMap in the default java package. There is an advantage of not needing an additional configuration because of saving cache data to the default Map type in memory, but it is poor for a real service. This is because dealing with cache requires a lot of skills but the ConcurrentHashMap is a structure in which complex caching cannot be used.

In my opinion, I recommend using this CacheManager for the demo or test application because it uses default Java packages which do not require configuration.

✔️ EhCacheCacheManager

The CacheManager is supported by the EhCache which is one of the popular cache frameworks in Java.

✔️ CaffeineCacheManager

The CacheManager is supported by the CaffeineCache which is rewritten GuavaCache for performance in Java 8. Caffeine is a rising one of the caching services because of its faster performance than EhCache.

✔️ CompositeCacheManager

This is for composite CacheManager one or more.

📌 @EnableCaching

To add caching to the methods, you have to declare @EnableCaching in Spring Framework.

You can apply it easily by annotating the configuration Class like the codes below.

✔ Code

@EnableCaching 
@Configuration
public class EhCacheConfiguration { /* ... */}

📌 @Cacheable

If @Cacheable annotation is set up on the method, the set method return value is stored.

If the method calculates data previously, the caching value exists in storage and the method is not necessary to calculate at each request because the stored data is returned instead.

The caching is saved on the base of cacheName. If it should be indicated in detailed individual values, it can be set up as the key name like the following example.

@Cacheable(cacheNames = "platformBooks") 
public Book getPlatformTeamBook(int bookId) { /* ... */}
// or@Cacheable(cacheNames = "platformBooks", key = "#root.target + #root.methodName + '_'+ #p0")
public Book getPlatformTeamBook(int bookId) { /* ... */}

@CacheEvict

The @CacheEvict annotation removes the stored caching data when the method is called. This is necessary for changing calculated data because there is a gap between existing stored caching data and calculating data.

@CacheEvict(value = "platformTeamBooks", allEntries = true) 
public Book insertPlatformTeamBook(BookVO bookVO) { /* ... */}

@CachePut

The @CachePut annotation use uses only storing cache.

Similar to @Cacheable annotation, @CachePut stores in the cache memory but its annotation does not use caching data, instead, it just only gets a purpose of storing. Instead, it only works for storage purposes.

@Cacheable(key = "testKey", condition="#caching")
public Object modifySome(boolean caching) {/* ... */}

--

--