Spring Boot + Hazelcast
In this tutorial, we will learn how to integrate Hazelcast with Spring Boot.
What is Hazelcast?
Hazelcast provides central, predictable scaling of applications through in-memory access to frequently used data and across an elastically scalable data grid. These techniques reduce the query load on databases and improve speed.
Create Spring Boot Application
Let's start to create Spring Boot Application from Spring Initializer and can follow below steps to integrate Hazelcast.
Pom.xml
Add spring-boot-starter-cache, hazelcast and hazelcast-spring dependencies in pom.xml.<?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.techgeeknext</groupId>
<artifactId>spring-boot-hazelcast-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-hazelcast-example</name>
<description>Example project for Spring Boot Hazelcast</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<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>
application.properties
Add h2 in-memory datasource properties.
## h2 techgeeknext-data.mv.db will be generated
spring.datasource.url=jdbc:h2:file:./techgeeknext-data
spring.datasource.platform=hsqldb
As we use HSQL to build the schema-hsqldb.sql file and define the scripts for initialization under resources folder.
DROP TABLE IF EXISTS employee;
CREATE TABLE employee (
empId VARCHAR(10) NOT NULL,
empName VARCHAR(100) NOT NULL
);
Employee Domain
Create Employee Domain Class.package com.techgeeknext.model;
import java.io.Serializable;
public class Employee implements Serializable{
private static final long serialVersionUID = 1L;
private String empId;
private String empName;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + "]";
}
}
Hazelcast configuration
Create the Hazelcast configuration class.package com.techgeeknext;
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("employees")
.setMaxSizeConfig(new MaxSizeConfig(200, MaxSizeConfig.MaxSizePolicy.FREE_HEAP_SIZE))
.setEvictionPolicy(EvictionPolicy.LRU)
.setTimeToLiveSeconds(20));
}
}
Service Layer
Create an interface to define the operations of the employee.package com.techgeeknext.service;
import java.util.List;
import com.techgeeknext.model.Employee;
public interface EmployeeService {
void insertEmployee(Employee emp);
void insertEmployees(List<Employee> employees);
List<Employee> getAllEmployees();
void getEmployeeById(String empid);
}
Create the implementation class with hazelcast configuration with @CacheConfig(cacheNames = "employees")
and @Cacheable()
.
package com.techgeeknext.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.techgeeknext.dao.EmployeeDao;
import com.techgeeknext.model.Employee;
import com.techgeeknext.service.EmployeeService;
@Service
@CacheConfig(cacheNames = "employees")
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
EmployeeDao employeeDao;
@Override
public void insertEmployee(Employee employee) {
employeeDao.insertEmployee(employee);
}
@Override
public void insertEmployees(List<Employee> employees) {
employeeDao.insertEmployees(employees);
}
@Override
@Cacheable()
public List<Employee> getAllEmployees() {
System.out.println("Employee Service Layer - Get All Employees");
return employeeDao.getAllEmployees();
}
@Override
public void getEmployeeById(String empId) {
Employee employee = employeeDao.getEmployeeById(empId);
System.out.println(employee);
}
}
DAO Layer
Create Dao interface for employee.package com.techgeeknext.dao;
import java.util.List;
import com.techgeeknext.model.Employee;
public interface EmployeeDao {
void insertEmployee(Employee cus);
void insertEmployees(List<Employee> employees);
List<Employee> getAllEmployees();
Employee getEmployeeById(String empId);
}
Create Dao implementation class.
package com.techgeeknext.dao.impl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import com.techgeeknext.dao.EmployeeDao;
import com.techgeeknext.model.Employee;
@Repository
public class EmployeeDaoImpl extends JdbcDaoSupport implements EmployeeDao{
@Autowired
DataSource dataSource;
@PostConstruct
private void initialize(){
setDataSource(dataSource);
}
@Override
public void insertEmployee(Employee emp) {
String sql = "INSERT INTO employee " +
"(empId, empName) VALUES (?, ?)" ;
getJdbcTemplate().update(sql, new Object[]{
emp.getEmpId(), emp.getEmpName()
});
}
@Override
public void insertEmployees(final List<Employee> employees) {
String sql = "INSERT INTO employee " + "(empId, empName) VALUES (?, ?)";
getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
Employee employee = employees.get(i);
ps.setString(1, employee.getEmpId());
ps.setString(2, employee.getEmpName());
}
public int getBatchSize() {
return employees.size();
}
});
}
@Override
public List<Employee> getAllEmployees(){
System.out.println("EmployeeDao - Get All Employees");
String sql = "SELECT * FROM employee";
List<Map<String, Object>> rows = getJdbcTemplate().queryForList(sql);
List<Employee> result = new ArrayList<Employee>();
for(Map<String, Object> row:rows){
Employee emp = new Employee();
emp.setEmpId((String)row.get("empId"));
emp.setEmpName((String)row.get("empName"));
result.add(emp);
}
return result;
}
@Override
public Employee getEmployeeById(String empId) {
String sql = "SELECT * FROM employee WHERE empId = ?";
return (Employee)getJdbcTemplate().queryForObject(sql, new Object[]{empId}, new RowMapper<Employee>(){
@Override
public Employee mapRow(ResultSet rs, int rwNumber) throws SQLException {
Employee emp = new Employee();
emp.setEmpId(rs.getString("empId"));
emp.setEmpName(rs.getString("empName"));
return emp;
}
});
}
}
Main Class
Create main class (SpringBootHazelcastExample) enabling hazelcast by using@EnableCaching
annotation.
package com.techgeeknext;
import com.techgeeknext.model.Employee;
import com.techgeeknext.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ApplicationContext;
import java.util.ArrayList;
import java.util.List;
@SpringBootApplication
@EnableCaching
public class SpringBootHazelcastExample {
@Autowired
EmployeeService employeeService;
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(SpringBootHazelcastExample.class, args);
EmployeeService employeeService = context.getBean(EmployeeService.class);
// Insert Employees in the Table
Employee emp= new Employee();
emp.setEmpId("111");
emp.setEmpName("John");
Employee emp1= new Employee();
emp1.setEmpId("222");
emp1.setEmpName("Miler");
Employee emp2= new Employee();
emp2.setEmpId("333");
emp2.setEmpName("Nick");
employeeService.insertEmployee(emp);
List<Employee> employees = new ArrayList<>();
employees.add(emp1);
employees.add(emp2);
employeeService.insertEmployees(employees);
System.out.println("Main Class - First Time retrieving Employee Record from Service Class");
employeeService.getAllEmployees().forEach(employee-> System.out.println(employee.toString()));
System.out.println("Main Class - Second Time onwards retrieving Employee Record from Hazelcast");
employeeService.getAllEmployees().forEach(employee-> System.out.println(employee.toString()));
}
}
Test
Once you run this Spring Boot Application and can see below output in console.2020-01-05 20:45:15.208 INFO 19560 --- [ main] c.t.SpringBootHazelcastExample : Started SpringBootHazelcastExample in 8.26 seconds (JVM running for 8.827)
Main Class - First Time retrieving Employee Record from Service Class
2020-01-05 20:45:15.344 INFO 19560 --- [ main] c.h.i.p.impl.PartitionStateManager : [192.168.43.52]:5701 [dev] [3.12.4] Initializing cluster partition table arrangement...
Employee Service Layer - Get All Employees
EmployeeDao - Get All Employees
Employee [empId=111, empName=John]
Employee [empId=222, empName=Miler]
Employee [empId=333, empName=Nick]
Main Class - Second Time onwards retrieving Employee Record from Hazelcast
Employee [empId=111, empName=John]
Employee [empId=222, empName=Miler]
Employee [empId=333, empName=Nick]
Download Source Code
The full source code for this article can be found on below.Download it here - Spring Boot + Hazelcast