Spring WebFlux + Redis
1. redis-reactive, embedded redis ์์กด์ฑ ์ถ๊ฐ
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'it.ozimov:embedded-redis:0.7.2'
...
}
2. redis์ ๋ฌธ์์ด์ key value๋ฅผ ์ฌ์ฉํ๋๋ก Bean ๋ฑ๋ก
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class BasicRedisConfig {
@Primary
@Bean
ReactiveRedisOperations<String, String> redisOperations(ReactiveRedisConnectionFactory factory) {
RedisSerializer<String> serializer = new StringRedisSerializer();
RedisSerializationContext<String, String> serializationContext = RedisSerializationContext
.<String, String>newSerializationContext()
.key(serializer)
.value(serializer)
.hashKey(serializer)
.hashValue(serializer)
.build();
return new ReactiveRedisTemplate<>(factory, serializationContext);
}
}
3. test ๋ฐ ๋ก์ปฌ test๋ฅผ ์ํ embedded redis ์ค์
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import redis.embedded.RedisServer;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Configuration
public class EmbeddedRedisConfig {
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void redisServer() {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
}
4. handler ์์ฑ
- loadData(): 10๋ง๊ฐ์ ๋ฐ์ดํฐ ๋ก๋ ๋ฉ์๋
- findReactorList(): ๋น๋๊ธฐ, ๋ ผ๋ธ๋กํน ๋ฐฉ์์ ๋ฉ์๋
- findNormalList(): ๋๊ธฐ, ๋ธ๋กํน ๋ฐฉ์์ ๋ฉ์๋
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Component
@RequiredArgsConstructor
public class BasicHandler {
private final ReactiveRedisConnectionFactory factory;
private final ReactiveRedisOperations<String, String> reactiveRedisOperations;
private final RedisTemplate<String , String> stringStringRedisTemplate;
private static final AtomicInteger count = new AtomicInteger(0);
public void loadData() {
List<String> data = new ArrayList<>();
IntStream.range(0, 100000).forEach(i -> data.add(UUID.randomUUID().toString()));
Flux<String> stringFlux = Flux.fromIterable(data);
factory.getReactiveConnection()
.serverCommands()
.flushAll()
.thenMany(stringFlux.flatMap(uid -> reactiveRedisOperations.opsForValue()
.set(String.valueOf(count.getAndAdd(1)), uid)))
.subscribe();
}
public Flux<String> findReactorList() {
return reactiveRedisOperations
.keys("*")
.flatMap(key -> reactiveRedisOperations.opsForValue().get(key));
}
public Flux<String> findNormalList() {
return Flux.fromIterable(Objects.requireNonNull(stringStringRedisTemplate.keys("*"))
.stream()
.map(key -> stringStringRedisTemplate.opsForValue().get(key))
.collect(Collectors.toList()));
}
}
5. router ๋ฑ๋ก
- ๋ฑ๋ก์ bean์ด๋ฆ์ด ๋ค๋ฅธ router์ ๊ฒน์น์ง ์๊ฒ ์กฐ์ฌํด์ผํจ. ๋์ผ ์ด๋ฆ์ bean 2๊ฐ ๋ง๋ค๋ ค๊ณ ํ๋ฉด์ ์คํจํ๊ฒ ๋จ
import com.webflux.study.handler.BasicHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
@Configuration
@RequiredArgsConstructor
public class BasicRouter {
private final BasicHandler basicHandler;
@Bean
public RouterFunction<ServerResponse> basicRoute() {
return RouterFunctions.route()
.GET("/reactive-list", serverRequest -> ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
.body(basicHandler.findReactorList(), String.class))
.GET("/normal-list", serverRequest -> ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
.body(basicHandler.findNormalList(), String.class))
.GET("/load", serverRequest -> { basicHandler.loadData(); return ServerResponse.ok()
.body(BodyInserters.fromValue("Load Data Completed")); })
.build();
}
}
์ถ์ฒ : https://wellbell.tistory.com/238
Last updated