In this article of Spring Boot, we will look at how to integrate Spring Boot with Caffeine Cache. We will inspect the Spring Boot auto configuration feature with the ability to hook the Caffeine cache transparently.
Introduction
Caffeine is a high performance Java 8 based caching library providing a near optimal hit rate. It provides an in-memory cache very similar to the Google Guava API. Spring Boot Cache starters auto-configured a CaffeineCacheManager
if it finds the Caffeine in the classpath. The Spring Framework provides support for transparently adding Caching to an application. Let’s see how to integrate Spring Boot with Caffeine Cache.
1. Maven dependencies
To enable Spring Boot support for Caffeine, we need to add following two dependencies in our Spring Boot application.
- Spring Boot caching stater.
- Caffeine cache provider.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.7.0</version>
</dependency>
Refer to the Caffeine website for the latest release.
2. Service Setup.
Let’s create a simple Customer Service which will return customer information from the underlying system. We will add the Spring framework caching abstraction on this layer using Caffeine Cache. Let’s look at our service class:
public interface CustomerService {
Customer getCustomer(final Long customerID);
}
// Implementation
@Service
@CacheConfig(cacheNames = {"customer"})
public class DefaultCustomerService implements CustomerService {
private static final Logger LOG = LoggerFactory.getLogger(DefaultCustomerService.class);
@Cacheable
@Override
public Customer getCustomer(Long customerID) {
LOG.info("Trying to get customer information for id {} ",customerID);
return getCustomerData(customerID);
}
private Customer getCustomerData(final Long id){
Customer customer = new Customer(id, "[email protected]", "Test Customer");
return customer;
}
}
There are a few important point to discuss:
- The
@CacheConfig
is a class level annotation and help to streamline caching configurations. - The
@Cacheable
annotation used to demarcate methods that are cacheable. In simple words, this annotation used to show caching API that we want to store results for this method into the cache so, on subsequent invocations, the value in the cache returned without execute the method.
[pullquote align=”normal”]If you are starting with caching, I highly recommend reading our article on the introduction to Spring Caching. [/pullquote]
Spring caching provides a very transparent way to enable caching. We have used no direct dependency from the Caffeine Cache in our code base, all these are taken care internally by Spring caching framework.
3. Caffeine Cache Configuration
Spring Boot provide several options to configure Caffeine cache on startup. We have the option to configure these properties either through configuration file (application.properties
or yml
) or programmatically. Let’s see how to configure Caffeine cache using application.properties
file:
spring.cache.cache-names=ccustomer
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
The spring.cache.cache-names
property creates customer
caches. The Caffeine spec define the cache maximum size as 500 and a time to live of 10 minutes.
3.1 Caffeine Java Configuration
If you like, we can also configure Caffeine cache using Java configuration. Let’s see how the Java configuration look like:
@Configuration
public class CaffeineCacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("customer");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
Caffeine < Object, Object > caffeineCacheBuilder() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(500)
.expireAfterAccess(10, TimeUnit.MINUTES)
.weakKeys()
.recordStats();
}
}
4. Running Application
Let’s run our application to see it in action:
@Component
public class CaffeineCacheApp implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(CaffeineCacheApp.class);
@Autowired
CustomerService customerService;
@Override
public void run(String...args) throws Exception {
LOG.info("Starting the Caffine cache testing process");
customerService.getCustomer(1 l); //No hit , since this is the first request.
customerService.getCustomer(2 l); //No hit , since this is the first request.
customerService.getCustomer(1 l); //hit , since it is already in the cache.
customerService.getCustomer(1 l); //hit , since it is already in the cache.
customerService.getCustomer(1 l); //hit , since it is already in the cache.
customerService.getCustomer(1 l); //hit , since it is already in the cache.
}
}
If you look at the output of the above program, this is how it look like:
2019-05-15 20:09:50.865 INFO 86848 --- [ main] com.javadevjournal.CaffeineCacheApp : Starting the Caffeine cache testing process
2019-05-15 20:09:50.879 INFO 86848 --- [ main] c.j.service.impl.DefaultCustomerService : Trying to get customer information for id 1
2019-05-15 20:09:50.882 INFO 86848 --- [ main] c.j.service.impl.DefaultCustomerService : Trying to get customer information for id 2
Once the customer data is in the cache, it serves all subsequent calls from the cache. Look at the logs, though we are calling getCustomer(1)
, multiple times but log statement got printed only once as all subsequent calls got served from the cache.
Summary
In this article, we saw how to integrate Spring Boot with Caffeine Cache. We checked the option to configure Caffeine using configuration files or through Java configuration. The source for this article is available on the GitHub.
Hi,
thx for hint to Caffeine
p.s.
spring.cache.cache-names=ccustomer
should be
spring.cache.cache-names=customer
i guess.
Is @Bean annotation missing on the CacheManager?
Thanks for the pointer.Corrected the example.
1. how to run the application. The app has 2 files one is @SpringBootApplication and one file which implements CommnadLineRunner.
2. I built the jar and ran the application, could see the log lines getting print for every customerService.getCustomer()
Hi Jaya,
There is another class DefaultCustomerService with following annotation @CacheConfig(cacheNames = {“customer”}).This is Spring standard cache abstraction.Check the complete example on the Github
https://github.com/umeshawasthi/javadevjournal/tree/master/Spring-Boot/spring-boot-caffeine-application