Spring Boot Hazelcast Caching Example Configuration
Hazelcast is a Distributed In-Memory Data Grid tool and can be used as a caching provider for the spring framework abstraction caching layer. Using caching can improve the overall performance of your system. In the following tutorial we demonstrate how to configure hazelcast caching with spring boot.
Project Structure
Maven Dependencies
We use Apache Maven to manage our project dependencies. To start, add the following dependencies to your project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.memorynotfound.springboot.caching</groupId>
<artifactId>hazelcast</artifactId>
<version>1.0.0-SNAPSHOT</version>
<url>https://memorynotfound.com</url>
<name>Spring Boot - ${project.artifactId}</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Framework Caching Support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-spring</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Hazelcast Caching Service
By annotating the play
method using the @Cacheable
annotation the result of the subsequent invocations will be cached. The @CacheEvict(allEntries=true)
clears all the entries from the cache. The @CacheConfig(cachenames="instruments")
registers every method annotated with the spring framework caching annotations with the specified cache.
package com.memorynotfound.springboot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
@Service
@CacheConfig(cacheNames = "instruments")
public class MusicService {
private static Logger log = LoggerFactory.getLogger(MusicService.class);
@CacheEvict(allEntries = true)
public void clearCache(){}
@Cacheable(condition = "#instrument.equals('trombone')")
public String play(String instrument) {
log.info("Executing: " + this.getClass().getSimpleName() + ".play(\"" + instrument + "\");");
return "paying " + instrument + "!";
}
}
Hazelcast Caching Configuration
If hazelcast is on the classpath, Spring Boot will auto-configure an HazelcastInstance
that you can inject in your application.
The HazelcastInstance
is only created if a configuration is found. In this example we show you two ways you can configure your HazelcastInstance
. The first, using Java Configuration. The second using an hazelcast.xml
XML configuration.
In these configuration examples we created a simple In-Memory local cache. You can further configure hazelcast to your specific needs if you need distributed caches or other advanced features. But for now, we kept it very simple. If you look for more advanced features, please read the hazelcast documentation.
Hazelcast Java Configuration
First, lets start by looking at the Hazelcast Java Configuration. We must annotate our configuration class using the @Configuration
annotation. Next we create a Config
bean and configure with appropriate settings.
package com.memorynotfound.springboot;
import com.hazelcast.config.Config;
import com.hazelcast.config.EvictionPolicy;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.MaxSizeConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class HazelcastConfiguration {
@Bean
public Config hazelCastConfig(){
return new Config()
.setInstanceName("hazelcast-instance")
.addMapConfig(
new MapConfig()
.setName("instruments")
.setMaxSizeConfig(new MaxSizeConfig(200, MaxSizeConfig.MaxSizePolicy.FREE_HEAP_SIZE))
.setEvictionPolicy(EvictionPolicy.LRU)
.setTimeToLiveSeconds(20));
}
}
Hazelcast XML Configuration
You can also configure Hazelcast using XML configuration. Add a hazelcast.xml
file to the src/main/resources
folder and spring boot will auto configure hazelcast for you. You can optionally configure the location of the hazelcast.xml
file in your properties or YAML file using spring.hazelcast.config
configuration property. This is the equivalent XML configuration as above.
<?xml version="1.0" encoding="UTF-8"?>
<hazelcast
xsi:schemaLocation="http://www.hazelcast.com/schema/config http://www.hazelcast.com/schema/config/hazelcast-config.xsd"
xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<map name="instruments">
<max-size>200</max-size>
<eviction-policy>LFU</eviction-policy>
<time-to-live-seconds>20</time-to-live-seconds>
</map>
</hazelcast>
# application.yml
spring:
hazelcast:
config: classpath:config/hazelcast.xml
# application.properties
spring.hazelcast.config=classpath:config/hazelcast.xml
Bootstrap Hazelcast Caching Application
We can simply enable the caching by annotating the class with @EnableCaching. We wrote a simple caching application to demonstrate the hazelcast caching. As you can see, we invoke the play
method multiple times. On every subsequent invocation, when trombone is passed as an argument the method invocation will be cached.
package com.memorynotfound.springboot;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
@EnableCaching
@SpringBootApplication
public class Application implements CommandLineRunner {
private static Logger log = LoggerFactory.getLogger(Application.class);
@Autowired
private MusicService musicService;
@Autowired
private CacheManager cacheManager;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
log.info("Spring Boot Hazelcast Caching Example Configuration");
log.info("Using cache manager: " + cacheManager.getClass().getName());
musicService.clearCache();
play("trombone");
play("guitar");
play("trombone");
play("bass");
play("trombone");
}
private void play(String instrument){
log.info("Calling: " + MusicService.class.getSimpleName() + ".play(\"" + instrument + "\");");
musicService.play(instrument);
}
}
Console Output
The previous application prints the following output to the console.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.4.RELEASE)
INFO - Spring Boot Hazelcast Caching Example Configuration
INFO - using cache manager: com.hazelcast.spring.cache.HazelcastCacheManager
INFO - Calling: MusicService.play("trombone");
INFO - Executing: MusicService.play("trombone");
INFO - Calling: MusicService.play("guitar");
INFO - Executing: MusicService.play("guitar");
INFO - Calling: MusicService.play("trombone");
INFO - Calling: MusicService.play("bass");
INFO - Executing: MusicService.play("bass");
INFO - Calling: MusicService.play("trombone");
Can you have both the application.yml version along with the Java version? So the application.yml can have the environment specific values like having a “management-center” on a docker-compose while keeping all the cache TTL values common?