Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c011e08

Browse files
authored
Merge pull request #5 from codej99/feature/reactive
Feature/reactive
2 parents c066565 + 591b0b1 commit c011e08

File tree

3 files changed

+196
-4
lines changed

3 files changed

+196
-4
lines changed

‎build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ dependencies {
2525
implementation 'org.springframework.boot:spring-boot-starter-web'
2626
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
2727
implementation 'org.springframework.boot:spring-boot-starter-cache'
28+
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
2829
implementation 'com.google.code.gson:gson'
2930
implementation 'com.h2database:h2'
3031
compileOnly 'org.projectlombok:lombok'
3132
runtimeOnly 'mysql:mysql-connector-java'
3233
annotationProcessor 'org.projectlombok:lombok'
3334
testImplementation 'org.springframework.boot:spring-boot-starter-test'
35+
testImplementation 'io.projectreactor:reactor-test:3.1.0.RELEASE'
3436
testCompileOnly 'org.projectlombok:lombok'
3537
}

‎src/main/java/com/redis/cluster/config/RedisCacheConfig.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import org.springframework.data.redis.cache.CacheKeyPrefix;
88
import org.springframework.data.redis.cache.RedisCacheConfiguration;
99
import org.springframework.data.redis.cache.RedisCacheManager;
10+
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
1011
import org.springframework.data.redis.connection.RedisConnectionFactory;
12+
import org.springframework.data.redis.core.ReactiveRedisTemplate;
1113
import org.springframework.data.redis.core.RedisTemplate;
1214
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
13-
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
14-
import org.springframework.data.redis.serializer.RedisSerializationContext;
15-
import org.springframework.data.redis.serializer.StringRedisSerializer;
15+
import org.springframework.data.redis.serializer.*;
1616

1717
import java.time.Duration;
1818
import java.util.HashMap;
@@ -52,7 +52,22 @@ public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFacto
5252
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
5353
redisTemplate.setConnectionFactory(connectionFactory);
5454
redisTemplate.setKeySerializer(new StringRedisSerializer());
55-
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
55+
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
5656
return redisTemplate;
5757
}
58+
59+
@Bean
60+
public ReactiveRedisTemplate<String, String> reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory) {
61+
RedisSerializer<String> serializer = new StringRedisSerializer();
62+
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(String.class);
63+
RedisSerializationContext serializationContext = RedisSerializationContext
64+
.<String, String>newSerializationContext()
65+
.key(serializer)
66+
.value(jackson2JsonRedisSerializer)
67+
.hashKey(serializer)
68+
.hashValue(jackson2JsonRedisSerializer)
69+
.build();
70+
71+
return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
72+
}
5873
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package com.redis.cluster;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.test.context.SpringBootTest;
8+
import org.springframework.data.geo.Point;
9+
import org.springframework.data.redis.connection.DataType;
10+
import org.springframework.data.redis.core.*;
11+
import org.springframework.test.context.junit4.SpringRunner;
12+
import reactor.core.publisher.Mono;
13+
import reactor.test.StepVerifier;
14+
15+
import java.util.*;
16+
17+
@Slf4j
18+
@RunWith(SpringRunner.class)
19+
@SpringBootTest
20+
public class ReactiveRedisClusterTest {
21+
22+
@Autowired
23+
private RedisTemplate<String, String> redisTemplate;
24+
25+
@Autowired
26+
private ReactiveRedisTemplate<String, String> reactiveRedisTemplate;
27+
28+
/**
29+
* 문자 데이터 구조 처리
30+
*/
31+
@Test
32+
public void opsValue() {
33+
ReactiveValueOperations<String, String> valueOps = reactiveRedisTemplate.opsForValue();
34+
Set<String> cacheKeys = new HashSet<>();
35+
// async process
36+
log.info("Step-1");
37+
for (int i = 0; i < 5000; i++) {
38+
String key = "value_" + i;
39+
cacheKeys.add(key);
40+
valueOps.set(key, String.valueOf(i));
41+
}
42+
log.info("Step-2");
43+
Mono<List<String>> values = valueOps.multiGet(cacheKeys);
44+
log.info("Step-3");
45+
StepVerifier.create(values)
46+
.expectNextMatches(x -> x.size() == 5000).verifyComplete();
47+
log.info("Step-4");
48+
}
49+
50+
/**
51+
* List 데이터 구조 처리 - 순서 있음. value 중복 허용
52+
*/
53+
@Test
54+
public void opsList() {
55+
ReactiveListOperations<String, String> listOps = reactiveRedisTemplate.opsForList();
56+
String cacheKey = "valueList";
57+
58+
// previous key delete - sync process
59+
redisTemplate.delete(cacheKey);
60+
61+
// async process
62+
Mono<Long> results = listOps.leftPushAll(cacheKey, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9");
63+
StepVerifier.create(results).expectNext(10L).verifyComplete();
64+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.LIST).verifyComplete();
65+
StepVerifier.create(listOps.size(cacheKey)).expectNext(10L).verifyComplete();
66+
StepVerifier.create(listOps.rightPop(cacheKey)).expectNext("0").verifyComplete();
67+
StepVerifier.create(listOps.leftPop(cacheKey)).expectNext("9").verifyComplete();
68+
}
69+
70+
/**
71+
* Hash 데이터 구조 처리 - 순서 없음. key 중복허용 안함, value 중복 허용
72+
*/
73+
@Test
74+
public void opsHash() {
75+
ReactiveHashOperations<String, String, String> hashOps = reactiveRedisTemplate.opsForHash();
76+
String cacheKey = "valueHash";
77+
Map<String, String> setDatas = new HashMap<>();
78+
for (int i = 0; i < 10; i++) {
79+
setDatas.put("key_" + i, "value_" + i);
80+
}
81+
82+
// previous key delete - sync
83+
redisTemplate.delete(cacheKey);
84+
85+
// async process
86+
StepVerifier.create(hashOps.putAll(cacheKey, setDatas)).expectNext(true).verifyComplete();
87+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.HASH).verifyComplete();
88+
StepVerifier.create(hashOps.size(cacheKey)).expectNext(10L).verifyComplete();
89+
StepVerifier.create(hashOps.get(cacheKey, "key_5")).expectNext("value_5").verifyComplete();
90+
StepVerifier.create(hashOps.remove(cacheKey, "key_5")).expectNext(1L).verifyComplete();
91+
}
92+
93+
/**
94+
* Set 데이터 구조 처리 - 순서 없음, value 중복 허용 안함
95+
*/
96+
@Test
97+
public void opsSet() {
98+
ReactiveSetOperations<String, String> setOps = reactiveRedisTemplate.opsForSet();
99+
String cacheKey = "valueSet";
100+
101+
// previous key delete - sync process
102+
redisTemplate.delete(cacheKey);
103+
104+
// async process
105+
StepVerifier.create(setOps.add(cacheKey, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9")).expectNext(10L).verifyComplete();
106+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.SET).verifyComplete();
107+
StepVerifier.create(setOps.size(cacheKey)).expectNext(10L).verifyComplete();
108+
StepVerifier.create(setOps.isMember(cacheKey, "5")).expectNext(true).verifyComplete();
109+
}
110+
111+
/**
112+
* SortedSet 데이터 구조 처리 - 순서 있음, value 중복 허용 안함
113+
*/
114+
@Test
115+
public void opsSortedSet() {
116+
ReactiveZSetOperations<String, String> zsetOps = reactiveRedisTemplate.opsForZSet();
117+
String cacheKey = "valueZSet";
118+
119+
// previous key delete - sync process
120+
redisTemplate.delete(cacheKey);
121+
122+
// async process
123+
List<ZSetOperations.TypedTuple<String>> tuples = new ArrayList<>();
124+
for (int i = 0; i < 10; i++) {
125+
tuples.add(new DefaultTypedTuple<>(String.valueOf(i), (double) i));
126+
}
127+
StepVerifier.create(zsetOps.addAll(cacheKey, tuples)).expectNext(10L).verifyComplete();
128+
StepVerifier.create(reactiveRedisTemplate.type(cacheKey)).expectNext(DataType.ZSET).verifyComplete();
129+
StepVerifier.create(zsetOps.size(cacheKey)).expectNext(10L).verifyComplete();
130+
StepVerifier.create(zsetOps.reverseRank(cacheKey, "9")).expectNext(0L).verifyComplete();
131+
}
132+
133+
/**
134+
* Geo 데이터 구조 처리 - 좌표 정보 처리, 타입은 zset으로 저장.
135+
*/
136+
@Test
137+
public void opsGeo() {
138+
ReactiveGeoOperations<String, String> geoOps = reactiveRedisTemplate.opsForGeo();
139+
String[] cities = {"서울", "부산"};
140+
String[][] gu = {{"강남구", "서초구", "관악구", "동작구", "마포구"}, {"사하구", "해운대구", "영도구", "동래구", "수영구"}};
141+
Point[][] pointGu = {{new Point(10, -10), new Point(11, -20), new Point(13, 10), new Point(14, 30), new Point(15, 40)}, {new Point(-100, 10), new Point(-110, 20), new Point(-130, 80), new Point(-140, 60), new Point(-150, 30)}};
142+
String cacheKey = "valueGeo";
143+
144+
// previous key delete - sync process
145+
redisTemplate.delete(cacheKey);
146+
147+
// async process
148+
Map<String, Point> memberCoordiateMap = new HashMap<>();
149+
for (int x = 0; x < cities.length; x++) {
150+
for (int y = 0; y < 5; y++) {
151+
memberCoordiateMap.put(gu[x][y], pointGu[x][y]);
152+
}
153+
}
154+
StepVerifier.create(geoOps.add(cacheKey, memberCoordiateMap)).expectNext(10L).verifyComplete();
155+
StepVerifier.create(geoOps.distance(cacheKey, "강남구", "동작구")).expectNextMatches(x -> x.getValue() == 4469610.0767).verifyComplete();
156+
StepVerifier.create(geoOps.position(cacheKey, "동작구")).expectNextMatches(x -> x.getX() == 14.000001847743988 && x.getY() == 30.000000249977013).verifyComplete();
157+
}
158+
159+
/**
160+
* HyperLogLog 데이터 구조 처리 - 집합의 원소의 개수 추정, 타입은 string으로 저장.
161+
*/
162+
@Test
163+
public void opsHyperLogLog() {
164+
ReactiveHyperLogLogOperations<String, String> hyperLogLogOps = reactiveRedisTemplate.opsForHyperLogLog();
165+
String cacheKey = "valueHyperLogLog";
166+
167+
// previous key delete - sync process
168+
redisTemplate.delete(cacheKey);
169+
170+
// async process
171+
String[] arr = {"1", "2", "2", "3", "4", "5", "5", "5", "5", "6", "7", "7", "7"};
172+
StepVerifier.create(hyperLogLogOps.add(cacheKey, arr)).expectNext(1L).verifyComplete();
173+
StepVerifier.create(hyperLogLogOps.size(cacheKey)).expectNext(7L).verifyComplete();
174+
}
175+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /