이제 필요한 소스를 만드는 중인데, 중간중간 잘 모르는 메소드나 타입, 어노테이션 등을 chatGPT에게 물어봐서 답변 받았던 거 중 몇가지 아카이브(?). 책, 챗지한테서 나온 답변 걍 복사해넣고 아주 조금 다듬은 정도.
개체 Entity : 개체는 한 도메인에서 명사를 나타낸다. / ex. 책
서비스 Service: 서비서는 도메인에 대한 사용사례를 정의하고 구현한다. / ex. 카탈로그에 책 추가
리포지터리 Repository: 데이터 소스와 독립적으로 데이터에 엑세스하기 위한 추상화 계층이다.
📌 BookRepository 인터페이스의 인메모리 구현이란?
✅ "인메모리 구현"이란, 데이터를 실제 데이터베이스(DB)에 저장하지 않고, 애플리케이션의 메모리(RAM)에서 저장하고 관리하는 방식을 의미합니다.
✅ 즉, BookRepository가 데이터베이스 대신 ConcurrentHashMap 같은 컬렉션을 이용해 데이터를 저장하는 방식으로 구현된 것을 뜻합니다.
🚀 인메모리 구현 vs 데이터베이스 구현
구현 방식 설명 예제
인메모리 구현 | 데이터를 애플리케이션 실행 중 메모리(RAM)에 저장 | Map<String, Book> books = new ConcurrentHashMap<>(); |
데이터베이스(DB) 구현 | 데이터를 실제 데이터베이스(MySQL, PostgreSQL 등)에 저장 | JPA, Hibernate를 사용하여 findById() 실행 |
📌 인메모리 방식의 특징
✅ 빠름 → DB를 거치지 않고 RAM에서 직접 데이터 조회
✅ 애플리케이션이 종료되면 데이터 사라짐
✅ 테스트에 많이 사용됨 (실제 DB 없이도 테스트 가능)
🔥 인메모리 구현 예제 (ConcurrentHashMap 사용) 104p
package com.polarbookshop.catalogservice.persistence;
import com.polarbookshop.catalogservice.domain.Book;
import com.polarbookshop.catalogservice.domain.BookRepository;
import org.springframework.stereotype.Repository;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
// BookRepository 인터페이스의 인메모리 구현
// @Repository: 클래스가 스프링에 의해 관리되는 리포지터리임을 표시
@Repository
public class InMemoryBookRepository implements BookRepository {
private static final Map<String, Book> books = new ConcurrentHashMap<>();
@Override
public Iterable<Book> findAll() {
return books.values();
}
@Override
public Optional<Book> findByIsbn(String isbn) {
return existsByIsbn(isbn) ? Optional.of(books.get(isbn)) : Optional.empty();
}
@Override
public boolean existsByIsbn(String isbn) {
return books.get(isbn) != null;
}
@Override
public Book save(Book book) {
books.put(book.isbn(), book);
return book;
}
@Override
public void deleteByIsbn(String isbn) {
books.remove(isbn);
}
}
ConcurrentHashMap<>
private static final Map<String, Book> books = new ConcurrentHashMap<>();
📌 ConcurrentHashMap<>란?
- HashMap과 비슷하지만 멀티스레드 환경에서도 안전(Thread-safe)한 맵입니다.
- 동시에 여러 스레드가 데이터를 읽고 써도 오류 없이 동작하도록 설계되어 있습니다.
- 일반적으로 HashMap은 멀티스레드에서 안전하지 않기 때문에, 여러 스레드가 접근할 가능성이 있는 경우 ConcurrentHashMap을 사용합니다.
📌 ConcurrentHashMap<> vs HashMap<> 비교
맵 타입멀티스레드 안전 여부동시 수정 가능 여부성능
HashMap<> | ❌ 안전하지 않음 | ❌ 불가능 | 빠름 |
ConcurrentHashMap<> | ✅ 안전함 | ✅ 가능 | 조금 느림 |
📌 예제
Map<String, Book> books = new ConcurrentHashMap<>();
books.put("12345", new Book("12345", "Java Basics"));
System.out.println(books.get("12345")); // Java Basics
➡ 여러 스레드가 books.put()을 동시에 실행해도 문제가 발생하지 않음.
Optional<T>
public Optional<Book> findByIsbn(String isbn)
📌 Optional<T>란?
- null을 직접 반환하는 대신, 값이 있을 수도 있고 없을 수도 있는 상황을 표현하기 위한 클래스입니다.
- null을 반환하면 NullPointerException이 발생할 수 있지만, Optional<T>를 사용하면 이를 방지할 수 있습니다.
- Optional<T> 내부적으로 값이 있으면 반환하고, 값이 없으면 empty 상태로 유지합니다.
📌 Optional<Book>의 의미
public Optional<Book> findByIsbn(String isbn)
➡ findByIsbn() 메서드는 책을 찾으면 Book을 반환하고, 찾지 못하면 Optional.empty()를 반환합니다.
Optional.of() & Optional.empty()
return existsByIsbn(isbn) ? Optional.of(books.get(isbn)) : Optional.empty();
📌 Optional.of(value)
- 값이 존재할 때 Optional<T> 객체를 생성합니다.
- Optional.of(books.get(isbn))는 isbn에 해당하는 Book 객체가 존재하면, Optional<Book>을 만들어 반환합니다.
📌 Optional.empty()
- 값이 없을 때 Optional<T> 객체를 생성합니다.
- Optional.empty()는 null 대신 안전하게 "값이 없음"을 표현하는 객체를 반환합니다.
📌 Optional.of() vs Optional.ofNullable() 차이
메서드null 허용 여부설명
Optional.of(value) | ❌ null이면 NullPointerException 발생 | 값이 무조건 있을 때 사용 |
Optional.ofNullable(value) | ✅ null일 수도 있음 | 값이 없을 수도 있을 때 사용 |
📌 예제
Book book = books.get("12345"); // 책이 존재할 수도 있고, 없을 수도 있음
Optional<Book> optionalBook = Optional.ofNullable(book); // 안전하게 Optional로 감싸기
➡ book이 null일 경우에도 Optional.empty()로 안전하게 처리됨.
🎯 최종 정리
코드 요소설명
ConcurrentHashMap<> | 멀티스레드 환경에서도 안전한 HashMap |
Optional<Book> | 값이 없을 수도 있는 상황을 안전하게 처리 |
Optional.of(value) | 값이 있을 때 Optional<T>로 감싸 반환 |
Optional.empty() | 값이 없을 때 안전하게 반환 |
'Cloud Native Spring in Action' 카테고리의 다른 글
스프링 MVC를 이용한 REST API 구현, 그리고 Httpie 설치와의 사투 (0) | 2025.02.06 |
---|---|
스프링 MVC를 이용한 RESTful 애플리케이션 구축(2) (1) | 2025.02.05 |
임베디드 서버로 작업 (0) | 2025.01.08 |
쿠버네티스로 컨테이너 관리 (0) | 2025.01.07 |
컨테이너를 통한 스프링 애플리케이션의 실행 (0) | 2025.01.07 |