Skip to content

Commit 2273d59

Browse files
author
akuksin
committed
add hazelcast with client-server topology
1 parent 2a82919 commit 2273d59

File tree

12 files changed

+312
-17
lines changed

12 files changed

+312
-17
lines changed

spring-boot/cache/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ dependencies {
2323
implementation 'org.springframework.boot:spring-boot-starter-web'
2424
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2525
implementation 'org.flywaydb:flyway-core'
26+
27+
compile("com.hazelcast:hazelcast:4.0.1")
28+
compile("com.hazelcast:hazelcast-spring:4.0.1")
29+
testCompile "org.testcontainers:testcontainers:1.12.5"
30+
2631
runtimeOnly 'com.h2database:h2'
2732
compileOnly 'org.projectlombok:lombok'
2833
annotationProcessor 'org.projectlombok:lombok'
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.reflectoring.cache.configiration;
2+
3+
4+
import com.hazelcast.client.HazelcastClient;
5+
import com.hazelcast.client.config.ClientConfig;
6+
import com.hazelcast.config.MapConfig;
7+
import com.hazelcast.core.HazelcastInstance;
8+
import com.hazelcast.spring.cache.HazelcastCacheManager;
9+
import org.springframework.cache.CacheManager;
10+
import org.springframework.cache.annotation.EnableCaching;
11+
import org.springframework.context.annotation.Bean;
12+
import org.springframework.context.annotation.Configuration;
13+
import org.springframework.context.annotation.Profile;
14+
15+
16+
@Configuration
17+
@EnableCaching
18+
@Profile("client")
19+
public class ClientCacheConfig {
20+
21+
@Bean
22+
ClientConfig config() {
23+
ClientConfig clientConfig = new ClientConfig();
24+
25+
MapConfig mapConfig = new MapConfig();
26+
mapConfig.setTimeToLiveSeconds(300);
27+
return clientConfig;
28+
}
29+
30+
@Bean
31+
HazelcastInstance hazelcastInstance() {
32+
return HazelcastClient.newHazelcastClient();
33+
}
34+
35+
@Bean
36+
CacheManager cacheManager() {
37+
return new HazelcastCacheManager(hazelcastInstance());
38+
}
39+
40+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.reflectoring.cache.configiration;
2+
3+
4+
import com.hazelcast.config.Config;
5+
import com.hazelcast.config.MapConfig;
6+
import org.springframework.cache.annotation.EnableCaching;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.context.annotation.Configuration;
9+
import org.springframework.context.annotation.Profile;
10+
11+
12+
@Configuration
13+
@EnableCaching
14+
@Profile("embedded")
15+
public class EmbeddedCacheConfig /*extends CachingConfigurerSupport*/ {
16+
17+
@Bean
18+
Config config(){
19+
Config config = new Config();
20+
21+
MapConfig mapConfig = new MapConfig();
22+
mapConfig.setTimeToLiveSeconds(300);
23+
//mapConfig.setMaxIdleSeconds(10);
24+
25+
config.getMapConfigs().put("cars", mapConfig);
26+
return config;
27+
}
28+
29+
}

spring-boot/cache/src/main/java/io/reflectoring/cache/dao/Car.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99
import javax.persistence.GeneratedValue;
1010
import javax.persistence.GenerationType;
1111
import javax.persistence.Id;
12+
import java.io.Serializable;
1213
import java.util.UUID;
1314

1415
@Entity
1516
@Data
1617
@NoArgsConstructor
1718
@AllArgsConstructor
1819
@Builder
19-
public class Car {
20+
public class Car implements Serializable {
2021

2122
@Id
2223
@GeneratedValue(strategy = GenerationType.AUTO)

spring-boot/cache/src/main/java/io/reflectoring/cache/rest/CarResource.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.reflectoring.cache.dao.Car;
44
import io.reflectoring.cache.service.CarService;
5+
import org.springframework.cache.CacheManager;
56
import org.springframework.http.HttpStatus;
67
import org.springframework.transaction.annotation.Transactional;
78
import org.springframework.web.bind.annotation.*;
@@ -15,10 +16,12 @@ public class CarResource {
1516

1617
private final CarService carService;
1718
private final CarMapper carMapper;
19+
private final CacheManager cacheManager;
1820

19-
public CarResource(CarService carService, CarMapper carMapper) {
21+
public CarResource(CarService carService, CarMapper carMapper, CacheManager cacheManager) {
2022
this.carService = carService;
2123
this.carMapper = carMapper;
24+
this.cacheManager = cacheManager;
2225
}
2326

2427
@PostMapping

spring-boot/cache/src/main/java/io/reflectoring/cache/service/CarService.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
import io.reflectoring.cache.dao.Car;
44
import io.reflectoring.cache.dao.CarRepository;
5+
import org.springframework.cache.CacheManager;
6+
import org.springframework.cache.annotation.CacheEvict;
7+
import org.springframework.cache.annotation.CachePut;
8+
import org.springframework.cache.annotation.Cacheable;
59
import org.springframework.stereotype.Service;
610

711
import java.util.UUID;
@@ -10,15 +14,18 @@
1014
public class CarService {
1115

1216
private final CarRepository carRepository;
17+
private final CacheManager cacheManager;
1318

14-
public CarService(CarRepository carRepository) {
19+
public CarService(CarRepository carRepository, CacheManager cacheManager) {
1520
this.carRepository = carRepository;
21+
this.cacheManager = cacheManager;
1622
}
1723

1824
public Car saveCar(Car car) {
1925
return carRepository.save(car);
2026
}
2127

28+
@CachePut(value = "cars")
2229
public Car update(Car car) {
2330
if (carRepository.existsById(car.getId())) {
2431
return carRepository.save(car);
@@ -27,13 +34,22 @@ public Car update(Car car) {
2734
throw new IllegalArgumentException("A car mus have an id to be updated");
2835
}
2936

37+
@Cacheable(value = "cars")
3038
public Car get(UUID uuid) {
3139
return carRepository.findById(uuid)
3240
.orElseThrow(() -> new IllegalStateException("car with id " + uuid + " was not found"));
3341
}
3442

43+
@CacheEvict(value = "cars")
3544
public void delete(UUID uuid) {
3645
carRepository.deleteById(uuid);
46+
System.out.println(cacheManager.getClass().getCanonicalName());
47+
// long cacheHits = ((HazelcastCacheManager) cacheManager).getHazelcastInstance().getMap("cars").getLocalMapStats().getHits();
48+
// System.out.println(((HazelcastCacheManager) cacheManager).getHazelcastInstance().getMap("cars").getLocalMapStats());
49+
// long cacheMisses = ((HazelcastCacheManager) cacheManager).getHazelcastInstance().getCacheManager().getCache("cars").getLocalCacheStatistics().getCacheMisses();
50+
//
51+
// System.out.println("hits:" + cacheHits);
52+
// System.out.println("misses:" + cacheMisses);
3753
}
3854

3955
}
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.reflectoring.cache;
2+
3+
import org.junit.jupiter.api.BeforeAll;
4+
import org.testcontainers.containers.FixedHostPortGenericContainer;
5+
import org.testcontainers.containers.GenericContainer;
6+
7+
public class AbstractIntegrationTest {
8+
9+
static GenericContainer firstMember =
10+
new FixedHostPortGenericContainer("hazelcast/hazelcast:4.0.1")
11+
.withFixedExposedPort(5701, 5701);
12+
13+
static GenericContainer secondMember =
14+
new FixedHostPortGenericContainer("hazelcast/hazelcast:4.0.1")
15+
.withFixedExposedPort(5702, 5701);
16+
17+
@BeforeAll
18+
public static void init() {
19+
firstMember.start();
20+
secondMember.start();
21+
}
22+
}

spring-boot/cache/src/test/java/io/reflectoring/cache/CacheApplicationTests.java

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package io.reflectoring.cache.rest;
2+
3+
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import io.reflectoring.cache.AbstractIntegrationTest;
6+
import org.junit.jupiter.api.Test;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
9+
import org.springframework.boot.test.context.SpringBootTest;
10+
import org.springframework.http.MediaType;
11+
import org.springframework.test.context.ActiveProfiles;
12+
import org.springframework.test.web.servlet.MockMvc;
13+
14+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
15+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
16+
17+
@SpringBootTest
18+
@AutoConfigureMockMvc
19+
@ActiveProfiles("client")
20+
class CarResourceClientCacheIntegrationTest extends AbstractIntegrationTest {
21+
22+
@Autowired
23+
private MockMvc mockMvc;
24+
25+
@Autowired
26+
private ObjectMapper objectMapper;
27+
28+
@Test
29+
void manageCar() throws Exception {
30+
// given
31+
CarDto newCarDto = CarDto.builder()
32+
.name("vw")
33+
.color("white")
34+
.build();
35+
36+
// when
37+
String response = mockMvc.perform(
38+
post("/cars")
39+
.content(objectMapper.writeValueAsString(newCarDto))
40+
.contentType(MediaType.APPLICATION_JSON)
41+
)
42+
// then
43+
.andExpect(status().isCreated())
44+
.andReturn()
45+
.getResponse()
46+
.getContentAsString();
47+
48+
mockMvc.perform(
49+
post("/cars")
50+
.content(objectMapper.writeValueAsString(newCarDto))
51+
.contentType(MediaType.APPLICATION_JSON)
52+
)
53+
// then
54+
.andExpect(status().isCreated());
55+
56+
CarDto carDto = objectMapper.readValue(response, CarDto.class);
57+
carDto.setName("bmw");
58+
59+
mockMvc.perform(
60+
put("/cars")
61+
.content(objectMapper.writeValueAsString(carDto))
62+
.contentType(MediaType.APPLICATION_JSON)
63+
)
64+
// then
65+
.andExpect(status().isOk());
66+
67+
// when
68+
mockMvc.perform(
69+
get("/cars/" + carDto.getId())
70+
.contentType(MediaType.APPLICATION_JSON)
71+
)
72+
// then
73+
.andExpect(status().isOk());
74+
75+
mockMvc.perform(
76+
get("/cars/" + carDto.getId())
77+
.contentType(MediaType.APPLICATION_JSON)
78+
)
79+
// then
80+
.andExpect(status().isOk());
81+
82+
mockMvc.perform(
83+
get("/cars/" + carDto.getId())
84+
.contentType(MediaType.APPLICATION_JSON)
85+
)
86+
// then
87+
.andExpect(status().isOk());
88+
89+
// when
90+
mockMvc.perform(
91+
delete("/cars/" + carDto.getId())
92+
)
93+
// then
94+
.andExpect(status().isNoContent());
95+
}
96+
}

0 commit comments

Comments
 (0)