Hazelcast – Spring Integration
Hazelcast supports an easy way to integrate with Spring Boot application. Let”s try to understand that via an example.
We will create a simple API application which provides an API to get employee information for a company. For this purpose, we will use Spring Boot driven RESTController along with Hazelcast for caching data.
Note that to integrate Hazelcast in Spring Boot, we will need two things −
-
Add Hazelcast as a dependency to our project.
-
Define a configuration (static or programmatic) and make it available to Hazelcast
Let’s first define the POM. Note that we have to specify Hazelcast JAR to use it in the Spring Boot 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.example</groupId> <artifactId>hazelcast</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project to explain Hazelcast integration with Spring Boot</description> <properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.0</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-all</artifactId> <version>4.0.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Also add hazelcast.xml to src/main/resources −
<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config http://www.hazelcast.com/schema/config/hazelcast-config-3.12.12.xsd" xmlns="http://www.hazelcast.com/schema/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <instance-name>XML_Hazelcast_Instance</instance-name> </hazelcast>
Define an entry point file for Spring Boot to use. Ensure that we have @EnableCaching specified −
package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @EnableCaching @SpringBootApplication public class CompanyApplication { public static void main(String[] args) { SpringApplication.run(CompanyApplication.class, args); } }
Let us define our employee POJO −
package com.example.demo; import java.io.Serializable; public class Employee implements Serializable{ private static final long serialVersionUID = 1L; private int empId; private String name; private String department; public Employee(Integer id, String name, String department) { super(); this.empId = id; this.name = name; this.department = department; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } @Override public String toString() { return "Employee [empId=" + empId + ", name=" + name + ", department=" + department + "]"; } }
And ultimately, let us define a basic REST controller to access employee −
package com.example.demo; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/v1/") class CompanyApplicationController{ @Cacheable(value = "employee") @GetMapping("employee/{id}") public Employee getSubscriber(@PathVariable("id") int id) throws InterruptedException { System.out.println("Finding employee information with id " + id + " ..."); Thread.sleep(5000); return new Employee(id, "John Smith", "CS"); } }
Now let us execute the above application, by running the command −
mvn clean install mvn spring-boot:run
You will notice that the output of the command would contain Hazelcast member information which mean Hazelcast Instance is automatically configured for us using hazelcast.xml configuration.
Members {size:1, ver:1} [ Member [localhost]:5701 - 91b3df1d-a226-428a-bb74-6eec0a6abb14 this ]
Now let us execute via curl or use browser to access API −
curl -X GET http://localhost:8080/v1/employee/5
The output of the API would be our sample employee.
{ "empId": 5, "name": "John Smith", "department": "CS" }
In the server logs (i.e. where Spring Boot application running), we see the following line −
Finding employee information with id 5 ...
However, note that it takes almost 5 secs (because of sleep we added) to access the information. But If we call the API again, the output of the API is immediate. This is because we have specified @Cacheable notation. The data of our first API call has been cached using Hazelcast as a backend.