Guide_Accessing Data Reactively with Redis

Dev.Hammy·2023년 12월 26일
0

Spring Guides

목록 보기
36/46

이 가이드는 비차단(non-blocking) Lettuce 드라이버를 사용하여 Redis와 상호 작용하기 위해 Spring Data를 사용하는 기능적(functional) 반응형(reactive) 애플리케이션을 생성하는 과정을 안내합니다.


Reactive Redis와 일반 Redis의 메시지 송수신 방식 차이

Reactive Redis

  • 제어권: 호출된 Reactive 함수 또는 메서드
  • 비동기/동기: 비동기적으로 작동
  • 논블로킹/블로킹: 논블로킹 방식

상황 설명:

Reactive Redis는 비동기 및 논블로킹 방식으로 동작합니다. 예를 들어, ReactiveRedisOperations를 사용하여 Redis에 요청을 보내면, 해당 메서드는 호출되고 데이터를 요청한 후 즉시 반환됩니다. 그러나 데이터가 준비될 때까지 다른 작업을 수행할 수 있습니다. 결과는 콜백(callback)이나 리액티브 스트림(Reactive Streams)을 통해 처리됩니다. 이 경우 데이터의 처리와 제어권은 콜백이나 리액티브 스트림을 처리하는 컴포넌트에게 있습니다.

일반 Redis

  • 제어권: 호출된 Redis 명령어 또는 함수
  • 비동기/동기: 대부분의 라이브러리는 동기적으로 작동하지만, 비동기 라이브러리도 있음
  • 논블로킹/블로킹: 블로킹 방식

상황 설명:

대부분의 일반 Redis 라이브러리는 동기적으로 작동합니다. 따라서 Redis 명령어를 호출하면 해당 명령이 완료될 때까지 대기하며, 결과가 반환될 때까지 다른 작업을 수행할 수 없습니다. 이러한 방식에서는 명령어를 호출한 코드가 결과가 준비될 때까지 제어권을 가지게 됩니다. 그러나 일부 비동기 Redis 라이브러리의 경우, 명령어를 호출하고 결과를 기다리지 않고 다른 작업을 수행할 수 있게 해주며, 결과는 콜백 등을 통해 처리됩니다.

요약하자면, Reactive Redis에서는 데이터 처리 및 제어권이 콜백이나 리액티브 스트림을 처리하는 컴포넌트에게 있으며, 일반 Redis에서는 데이터 처리 및 제어권이 명령어를 호출한 코드에게 있거나, 비동기 라이브러리의 경우 콜백을 통해 처리됩니다.


Redis에서 데이터의 저장

Redis는 디스크나 메모리와 같은 물리적인 저장 공간에 데이터를 보관하는 인메모리 데이터베이스입니다. 기본적으로 Redis는 메모리에 데이터를 저장하며, 디스크에도 영구적으로 저장할 수 있도록 설정할 수 있습니다.

Redis의 데이터는 키-값(Key-Value) 형태로 저장되며, 각 키에는 해당하는 값이 할당됩니다. Redis는 다양한 데이터 구조를 지원하며, 문자열, 리스트, 해시, 집합, 정렬 집합 등 다양한 데이터 타입을 저장할 수 있습니다.

데이터가 메모리에 저장되므로 Redis는 빠른 읽기와 쓰기 속도를 제공합니다. 그러나 메모리의 용량 한계가 있기 때문에 Redis의 설정에 따라 메모리가 가득 차게 되면 LRU(Least Recently Used) 등의 정책에 따라 데이터를 삭제하거나 디스크에 영구적으로 저장합니다.

따라서 Redis는 디스크에 영속적으로 데이터를 저장할 수 있고, 캐시, 세션 관리, 메시지 브로커 등 다양한 용도로 사용되는데, 이때 디스크 저장 옵션을 설정하면 Redis는 메모리와 디스크 간에 데이터를 보관합니다.


무엇을 구축할 것인가

Spring Data Redis 및 Project Reactor를 사용하여 Redis 데이터 저장소와 반응적으로 상호 작용하고 차단(blocking) 없이 Coffee 객체를 저장하고 검색하는 Spring 애플리케이션을 구축합니다. 이 애플리케이션은 Reactive Streams 사양을 기반으로 하는 Reactor의 Publisher 구현, 즉 Mono(0 또는 1 값을 반환하는 publisher용) 및 Flux(0~n 값을 반환하는 publisher용)를 사용합니다.

Starting with Spring Initializr

Standing up a Redis server

메시징 애플리케이션을 구축하기 전에 메시지 수신 및 전송을 처리할 서버를 설정해야 합니다.

Redis는 메시징 시스템과 함께 제공되는 오픈 소스 BSD 라이선스 키-값 데이터 저장소입니다. 서버는 https://redis.io/download에서 무료로 사용할 수 있습니다.

설치 과정은 다른 포스트 참고

Create a Domain Class

커피 카탈로그에 보관하려는 커피 유형을 나타내는 클래스를 만듭니다. : src/main/java/com/example/demo/Coffee.java

package com.example.demo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Coffee {
  private String id;
  private String name;
}

이 예제에서는 Lombok을 사용하여 생성자 및 소위 "데이터 클래스" 메서드(accessors/mutators, equals(), toString(), & hashCode())에 대한 상용구 코드를 제거했습니다.

Create a Configuration Class

반응형 Redis 작업을 지원하는 Spring Bean을 포함하는 클래스를 만듭니다. src/main/java/com/example/demo/CoffeeConfiguration.java



import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class CoffeeConfiguration {
  @Bean
  ReactiveRedisOperations<String, Coffee> redisOperations(ReactiveRedisConnectionFactory factory) {
    Jackson2JsonRedisSerializer<Coffee> serializer = new Jackson2JsonRedisSerializer<>(Coffee.class);

    RedisSerializationContext.RedisSerializationContextBuilder<String, Coffee> builder =
        RedisSerializationContext.newSerializationContext(new StringRedisSerializer());

    RedisSerializationContext<String, Coffee> context = builder.value(serializer).build();

    return new ReactiveRedisTemplate<>(factory, context);
  }

}

@Configurable@Configuration 차이

간단히 말해서, @Configurable은 객체를 스프링 컨텍스트로 주입하기 위해 사용되는 반면, @Configuration은 스프링의 설정 정보를 포함하고 있는 클래스임을 선언하는 데 사용됩니다.

  1. @Configurable:

    • @Configurable은 스프링에서 자동 와이어링(의존성 주입)을 허용하기 위해 사용됩니다.
    • 주로 AspectJ 컴파일 타임 위빙 또는 스프링 컨텍스트의 EnableLoadTimeWeaving 설정과 함께 사용됩니다.
    • 엔티티 클래스 등 스프링이 관리하지 않는 객체에서 스프링 빈을 사용하고 싶을 때 사용됩니다. 이를 위해 해당 클래스에 @Configurable을 붙이고 AspectJ 또는 load-time weaving을 설정하여 해당 클래스의 인스턴스가 스프링 빈처럼 관리되도록 할 수 있습니다.
  2. @Configuration:

    • @Configuration은 스프링 설정 클래스를 정의할 때 사용됩니다.
    • 이 어노테이션을 사용하여 자바 기반의 스프링 설정을 정의하고, @Bean 어노테이션을 사용하여 빈을 생성하고 구성합니다.
    • 이 클래스는 일반적으로 @ComponentScan, @Import, @PropertySource 등 다른 설정 어노테이션과 함께 사용되며, 스프링 애플리케이션 컨텍스트를 초기화하는 데 필요한 설정 정보를 제공합니다.

Reactive Redis와 일반 Redis의 컴포넌트 대응

  1. ReactiveRedisOperations
  • 일반적인 웹에서: RedisTemplate 또는 StringRedisTemplate
  • 설명: Redis 데이터와 상호작용하는 데 사용되는 인터페이스. 키-값 형태의 데이터를 읽고 쓰는 기능을 제공합니다.
  1. ReactiveRedisTemplate<>(factory, context)
  • 일반적인 웹에서: RedisTemplate 또는 StringRedisTemplate
  • 설명: ReactiveRedisOperations의 구현체. Redis에 비동기적으로 데이터를 저장하고 검색하는 데 사용됩니다. Reactive 스타일의 Redis 작업을 수행할 수 있게 해줍니다.
  1. ReactiveRedisConnectionFactory
  • 일반적인 웹에서: RedisConnectionFactory
  • 설명: Redis 서버와의 연결을 설정하고 관리하는 팩토리 인터페이스. 연결을 생성하고 관리하는 역할을 담당합니다.
  1. RedisSerializationContext
  • 일반적인 웹에서: RedisSerializer
  • 설명: Redis에 데이터를 저장하고 검색할 때 사용되는 직렬화 및 역직렬화를 구성하는 클래스. 데이터를 직렬화하고 역직렬화하는 방법을 정의합니다.

예제 코드 해석

이 코드는 Redis와 상호작용하기 위한 스프링 빈을 구성하는 CoffeeConfiguration 클래스입니다. 여기서 사용된 주요 요소들을 설명해드릴게요.

  1. @Configuration: 이 어노테이션은 이 클래스가 스프링의 구성 클래스임을 나타냅니다. 따라서 이 클래스에서는 스프링 빈(bean)을 정의하고 구성할 수 있습니다.

  2. @Bean: 이 어노테이션은 해당 메서드가 빈을 생성하고 스프링 컨테이너에 등록하는 역할을 합니다.

  3. ReactiveRedisOperations<String, Coffee> redisOperations(ReactiveRedisConnectionFactory factory): 이 메서드는 Reactive Redis 연산을 수행하기 위한 ReactiveRedisOperations 빈을 생성합니다. 이 빈은 Redis와 상호작용할 수 있는 메서드를 제공합니다. 메서드는 ReactiveRedisConnectionFactory를 매개변수로 받아와 Redis 연결 팩토리를 주입받습니다.

  4. Jackson2JsonRedisSerializer: 이 클래스는 Jackson을 사용하여 Java 객체를 JSON 형식으로 직렬화/역직렬화할 수 있는 Redis Serializer입니다. 여기서는 Coffee 객체를 JSON으로 직렬화하는데 사용됩니다.

  5. RedisSerializationContext: Redis 직렬화 컨텍스트를 구성합니다. StringRedisSerializer를 키(key)에 사용하고, Jackson2JsonRedisSerializer를 값(value)에 사용하여 Redis에 저장될 데이터의 직렬화 형식을 설정합니다.

  6. new ReactiveRedisTemplate<>(factory, context): ReactiveRedisTemplate을 생성하고, 위에서 구성한 연결 팩토리와 직렬화 컨텍스트를 사용하여 Redis와 상호작용할 수 있는 Reactive Redis 템플릿을 생성합니다.

이 코드는 Reactive 스타일의 Redis 작업을 위해 Redis 연결을 설정하고, Coffee 객체를 JSON으로 직렬화하여 Redis에 저장하고 검색할 수 있는 기능을 스프링 빈으로 구성하고 있어요.


Create a Spring Bean to Load Data

애플리케이션을 시작할 때 애플리케이션에 대한 샘플 데이터를 로드하기 위해 Spring Bean을 생성합니다.

애플리케이션을 여러 번 (다시) 시작할 수 있으므로 먼저 이전 실행에서 여전히 존재할 수 있는 데이터를 제거해야 합니다. 이는 flashAll()(Redis) 서버 명령을 사용하여 수행합니다. 기존 데이터를 플러시한 후에는 작은 Flux를 만들고 각 커피 이름을 Coffee 객체에 매핑한 다음 반응형 Redis 저장소에 저장합니다. 그런 다음 저장소에서 모든 값을 쿼리하고 표시합니다.

src/main/java/com/example/demo/CoffeeLoader.java

import jakarta.annotation.PostConstruct;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.UUID;

@Component
public class CoffeeLoader {
    private final ReactiveRedisConnectionFactory factory;
    private final ReactiveRedisOperations<String, Coffee> coffeOps;
    
    public CoffeeLoader(ReactiveRedisConnectionFactory factory, ReactiveRedisOperations<String, Coffee> coffeeOps) {
        this.factory = factory;
        this.coffeOps = coffeeOps;
    }
   
    @PostConstruct
    public void loadData() {
        factory.getReactiveConnection().serverCommands().flushAll().thenMany(
            Flux.just("Jet Black Redis", "Darth Redis", "Black Alert Redis")
                .map(name -> new Coffee(UUID.randomUUID().toString(), name))
                .flatMap(coffee -> coffeOps.opsForValue().set(coffee.getId(), coffee)))
            .thenMany(coffeOps.keys("*")
                .flatMap(coffeOps.opsForValue()::get))
            .subscribe(System.out::println);
    }
}

RedisTemplate 의 opsFor 메서드

  1. opsForValue()

    • opsForValue() 메서드는 Redis의 Key-Value 구조의 Value에 대한 작업을 수행합니다.
    • ValueOperations 반환
    • 주요 메서드:
      • set(K key, V value): 주어진 키에 값을 설정합니다.
      • get(K key): 주어진 키의 값을 가져옵니다.
      • increment(K key): 숫자 값을 증가시킵니다.
      • delete(K key): 주어진 키와 해당 값을 삭제합니다.
  2. opsForList()

    • opsForList() 메서드는 Redis의 리스트 구조에 대한 작업을 수행합니다.
    • ListOperations 반환
    • 주요 메서드:
      • leftPush(K key, V value): 리스트 왼쪽에 값을 추가합니다.
      • rightPop(K key): 리스트 오른쪽에서 값을 꺼냅니다.
      • size(K key): 리스트의 크기를 가져옵니다.
      • trim(K key, long start, long end): 리스트를 잘라서 원하는 부분만 남깁니다.
  3. opsForSet()

    • opsForSet() 메서드는 Redis의 집합 구조에 대한 작업을 수행합니다.
    • SetOperations 반환
    • 주요 메서드:
      • add(K key, V... values): 집합에 값을 추가합니다.
      • members(K key): 집합의 모든 멤버를 가져옵니다.
      • size(K key): 집합의 크기를 가져옵니다.
      • remove(K key, V... values): 집합에서 값을 제거합니다.
  4. opsForHash()

    • opsForHash() 메서드는 Redis의 해시 구조에 대한 작업을 수행합니다.
    • HashOperations 반환
    • 주요 메서드:
      • put(K key, HK hashKey, HV value): 해시에 값을 추가합니다.
      • get(K key, Object hashKey): 해시에서 특정 키의 값을 가져옵니다.
      • delete(K key, Object... hashKeys): 해시에서 키와 해당 값을 제거합니다.

예제 코드 요소

  1. Flux: Reactor 라이브러리의 핵심 요소 중 하나로, Reactive Streams 스펙을 따르는 Publisher입니다. 여러 개의 데이터를 생성하고 비동기적으로 처리할 수 있는 시퀀스를 나타내는데 사용됩니다. 여러 값을 생성할 수 있는데, 이 때 Flux는 0부터 N개의 요소를 처리할 수 있습니다.
  • Flux.just:

    • Flux.just는 주어진 값들을 이용하여 Flux를 생성하는 메서드입니다.
    • 0개 이상의 값을 가질 수 있으며, 주어진 값들을 순서대로 내보냅니다.
    • 예를 들어, Flux.just(1, 2, 3)은 1, 2, 3의 값을 차례대로 내보내는 Flux를 생성합니다.
     Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
  • thenMany:

    • thenMany는 이전 작업이 완료된 후에 다른 Flux나 Mono를 실행하는데 사용됩니다.
    • 보통 비동기 작업이 순차적으로 수행되어야 할 때 사용됩니다.
    • thenMany는 Mono나 Flux에서 사용할 수 있으며, 다른 Flux나 Mono를 반환하거나 연결하는데 사용됩니다.
    Flux<Integer> flux1 = Flux.just(1, 2, 3);
     Flux<Integer> flux2 = Flux.just(4, 5, 6);
    
     flux1.thenMany(flux2).subscribe(System.out::println);
    // flux1이 완료된 후 flux2의 값을 차례로 출력합니다.
  1. map과 flatMap의 차이:

    • map: 스트림 내의 각 요소에 함수를 적용하여 새로운 요소로 변환합니다. 즉, 각 요소를 일대일로 매핑하여 변환합니다.
    • flatMap: 각 요소를 어떤 함수에 적용하고 그 결과로 생성된 여러 Flux나 Mono를 1개의 Flux로 평탄화(flatten)합니다. 즉, 여러 Flux를 하나로 합치는 작업을 수행합니다.
  2. System.out::println: 이것은 메서드 레퍼런스(Method Reference)입니다. Java 8부터 도입된 기능으로, 람다식으로 표현된 메서드를 축약해서 표현할 수 있는 방법 중 하나입니다. System.out.println()을 사용하여 콘솔에 출력하는 메서드를 가리킵니다. ::은 메서드 레퍼런스를 사용할 때의 구분자입니다. System.out::println은 메서드 레퍼런스로, println() 메서드를 가리킵니다. 이것을 subscribe 시 사용하면 각 요소를 println 메서드에 전달하여 출력합니다.

예제 코드 해석

이 코드는 CoffeeLoader라는 Spring @Component입니다. 클래스가 생성되고, 모든 의존성이 주입된 후에 @PostConstruct가 붙은 메서드가 실행됩니다. 따라서 CoffeeLoader 클래스가 생성된 후에 @PostConstruct가 달린 loadData() 메서드가 실행되어 Redis 데이터를 초기화하고 작업을 수행하게 됩니다

  1. ReactiveRedisConnectionFactoryReactiveRedisOperations를 필드로 주입받습니다. 이는 Reactive Redis에 연결하고 데이터를 처리하기 위한 연결과 작업을 수행할 수 있게 합니다.

  2. loadData() 메서드는 애플리케이션이 시작될 때 실행됩니다. 이 메서드는 Redis의 데이터를 모두 지우고(flushAll()) 새로운 데이터를 저장합니다.

  3. Flux.just("Jet Black Redis", "Darth Redis", "Black Alert Redis")는 세 가지 커피 종류를 Flux로 생성합니다.

  4. map(name -> new Coffee(UUID.randomUUID().toString(), name))는 각 커피 종류마다 UUID와 이름을 가진 Coffee 객체를 생성합니다.

  5. flatMap(coffee -> coffeOps.opsForValue().set(coffee.getId(), coffee))는 생성된 Coffee 객체를 Redis에 저장합니다. opsForValue().set()을 사용하여 각 Coffee 객체를 Redis의 Key-Value 형태로 저장합니다.

  6. coffeOps.keys("*").flatMap(coffeOps.opsForValue()::get)는 Redis에 저장된 모든 데이터를 가져옵니다. keys("*")로 모든 키를 가져온 뒤, 각 키에 대해 opsForValue().get()을 통해 해당 값을 가져옵니다.

  7. subscribe(System.out::println)은 가져온 데이터를 출력합니다. 즉, Redis에 저장된 모든 Coffee 객체를 가져와서 출력합니다.


Create a RestController

애플리케이션에 외부 인터페이스를 제공하기 위해 RestController를 만듭니다.

import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

@RestController
public class CoffeeController {
    private final ReactiveRedisOperations<String, Coffee> coffeeOps;

    CoffeeController(ReactiveRedisOperations<String, Coffee> coffeeOps) {
        this.coffeeOps = coffeeOps;
    }

    @GetMapping("/coffees")
    public Flux<Coffee> all() {
        return coffeeOps.keys("*").flatMap(coffeeOps.opsForValue()::get)
    }
}

flatMap에서 메서드 레퍼런스 대신 람다 표현식을 사용하여 같은 코드를 표현하려면 아래와 같이 할 수 있습니다.

@GetMapping("/coffees")
public Flux<Coffee> all() {
    return coffeeOps.keys("*").flatMap(key -> coffeeOps.opsForValue().get(key));
}

Make the Application Executable

외부 애플리케이션 서버에 배포하기 위해 이 서비스를 기존 WAR 파일로 패키징할 수 있지만 여기에 표시된 더 간단한 접근 방식을 사용하면 독립 실행형(single executable) 애플리케이션을 만들 수 있습니다. 좋은 오래된 Java main() 메소드에 의해 구동되는 단일 실행 가능한 JAR 파일에 모든 것을 패키지합니다. 그 과정에서 외부 인스턴스에 배포하는 대신 Netty를 HTTP 런타임으로 비동기 "컨테이너(container)"에 내장(embedding)하기 위한 Spring의 지원을 사용합니다.

src/main/java/com/example/demo/DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

Netty를 HTTP 런타임으로 비동기 '컨테이너(container)'에 내장

  1. Netty:

    • Netty는 네트워크 애플리케이션을 개발하기 위한 Java 기반의 비동기 이벤트 드리븐 네트워크 프레임워크입니다. 네트워크 통신에 관련된 다양한 기능과 기술을 제공하여 비동기 방식으로 빠르고 확장 가능한 네트워크 애플리케이션을 구축할 수 있게 합니다.
  2. HTTP 런타임으로 내장:

    • 여기서 HTTP 런타임으로 내장되는 것은 Netty가 HTTP 프로토콜을 처리하는 데 사용된다는 것을 의미합니다. Netty는 HTTP 요청을 비동기적이고 논블로킹 방식으로 처리할 수 있는 능력을 갖추고 있습니다.
  3. 비동기 '컨테이너(container)':

    • 여기서 '컨테이너'는 Netty가 동작하는 환경이라고 생각할 수 있습니다. Netty는 HTTP 요청을 비동기적으로 처리하고 응답을 생성하는 데 사용될 수 있는 런타임 환경을 제공합니다. 이는 일반적인 서블릿 기반의 동기적인 방식보다 비동기적으로 동작하는 컨테이너로 볼 수 있습니다.

요약하면, "Netty를 HTTP 런타임으로 비동기 '컨테이너(container)'에 내장"이라는 말은 Netty가 HTTP 프로토콜을 처리하는 비동기적인 환경(컨테이너)에서 동작한다는 것을 의미합니다. Netty를 사용하면 비동기적이고 효율적인 방식으로 HTTP 요청을 처리할 수 있는 환경을 제공할 수 있습니다.


용어 : 런타임 환경 / 컨테이너 / 컨텍스트

  1. 런타임 환경(Runtime Environment):

    • 런타임 환경은 어떤 프로그램이 실행될 때 동작하는 환경을 가리킵니다. 이는 특정 프로그래밍 언어나 플랫폼에서 프로그램이 실행되기 위해 필요한 라이브러리, 패키지, 런타임 시스템 등을 포함합니다.
    • 예를 들어, Java 프로그램의 런타임 환경은 JVM(Java Virtual Machine)과 Java 런타임 라이브러리 등을 포함합니다. Python의 경우에는 Python 인터프리터와 관련된 라이브러리가 런타임 환경입니다.
  2. 컨테이너(Container):

    • 컨테이너는 격리된 환경에서 애플리케이션이 실행되도록 하는 기술을 말합니다. 가상화 기술 중 하나로, 운영체제 수준에서 여러 애플리케이션을 격리하여 실행할 수 있게 해줍니다.
    • 컨테이너는 독립적인 파일 시스템, 환경 변수, 네트워크, CPU, 메모리 등을 갖춘 격리된 환경을 제공하여 애플리케이션을 실행합니다. Docker와 Kubernetes는 컨테이너 기술을 관리하고 배포하는 데 사용되는 대표적인 도구입니다.
  3. 스프링 컨테이너(Spring Container):

    • 스프링에서는 IoC(Inversion of Control) 컨테이너 또는 스프링 컨테이너라고도 부릅니다. 이는 스프링 프레임워크에서 제공하는 핵심 컨테이너입니다. 스프링 컨테이너는 빈(bean) 객체를 생성하고 관리하며, 의존성 주입(Dependency Injection)을 통해 이들을 연결해줍니다.
  4. 스프링 컨텍스트(Spring Context):

    • 스프링 컨텍스트는 스프링 애플리케이션에서 객체들 간의 상호작용 및 설정 정보를 가지고 있는 객체입니다. ApplicationContext 인터페이스를 구현한 것이 스프링 컨텍스트입니다. 스프링 컨텍스트는 빈들의 라이프사이클 관리, 빈의 생성 및 관리, 리소스 로딩, 이벤트 발행 등의 작업을 수행합니다.

TCP/IP, 3-way Handshaking

3-way handshake는 TCP 연결을 설정하는 과정으로, 일반적으로 동기적이고 블로킹되는 작업입니다.

3-way handshake는 TCP 연결을 초기화하기 위해 클라이언트가 서버에게 SYN 패킷을 보내고, 서버가 이에 응답하여 SYN-ACK 패킷을 보내고, 마지막으로 클라이언트가 ACK 패킷을 보내는 과정입니다. 이러한 과정은 일반적으로 동기적이며, 연결이 설정될 때까지 기다리며 블로킹될 수 있습니다.

이 과정은 TCP/IP 프로토콜 스택에서 일어나며, 동기/블로킹 방식으로 작동합니다. 이와 관련하여 비동기적이거나 논블로킹인 HTTP와는 직접적인 연관성은 없습니다. HTTP는 TCP/IP 위에서 동작하며, TCP 연결 설정을 위한 3-way handshake는 HTTP 요청/응답과는 별개로 TCP/IP 수준에서 처리됩니다.


Test the application

실행 로그

 :: Spring Boot ::                (v3.2.1)

2024-01-04T13:45:09.770+09:00  INFO 11958 --- [           main] g.s.SpringDataReactiveRedisApplication   : Starting SpringDataReactiveRedisApplication using Java 17.0.9 with PID 11958 (/home/dev-hammy/IdeaProjects/SpringBoot_Guides/spring-data-reactive-redis/build/classes/java/main started by dev-hammy in /home/dev-hammy/IdeaProjects/SpringBoot_Guides/spring-data-reactive-redis)
2024-01-04T13:45:09.773+09:00  INFO 11958 --- [           main] g.s.SpringDataReactiveRedisApplication   : No active profile set, falling back to 1 default profile: "default"
2024-01-04T13:45:10.532+09:00  INFO 11958 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode
2024-01-04T13:45:10.534+09:00  INFO 11958 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data Redis repositories in DEFAULT mode.
2024-01-04T13:45:10.560+09:00  INFO 11958 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 11 ms. Found 0 Redis repository interfaces.
Coffee(id=d2b4ea7f-b872-4c31-b602-0771e2d86cb5, name=Black Alert Redis)
Coffee(id=4439dd73-919c-4f56-8aee-c6df817d5282, name=Jet Black Redis)
Coffee(id=66ddf2e9-f094-4931-861b-64214fba032d, name=Darth Redis)
2024-01-04T13:45:12.182+09:00  INFO 11958 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
2024-01-04T13:45:12.195+09:00  INFO 11958 --- [           main] g.s.SpringDataReactiveRedisApplication   : Started SpringDataReactiveRedisApplication in 3.028 seconds (process running for 4.32)

0개의 댓글