JVM은 싱글 프로세스 기반의 애플리케이션이지만, 그 안에서 여러 스레드가 동시에 동작한다. 내가 생각하는 이 구조의 핵심은 다음과 같다.
즉, 자바는 기본적으로 멀티스레딩 환경을 전제로 만들어진 언어이며, 이 점은 이후 웹 요청 처리나 비동기 처리에서 반드시 고려해야 한다.
Spring Boot에서 HTTP 요청이 들어오면 어떻게 처리될까? 이번 세미나에서 가장 실질적인 흐름을 이해할 수 있었던 부분이다.
이 구조는 스레드풀 기반 요청 처리 구조라고 부르며, 핵심은 "요청 하나당 스레드 하나가 배정된다"는 점이다.
요청을 처리하는 중 DB 작업이 필요한 경우, 워커 스레드는 직접 DB에 접근하지 않는다. 대신, Spring은 HikariCP라는 커넥션 풀 라이브러리를 통해 미리 만들어둔 DB 연결 객체(Connection)를 재활용한다.
🔸 적절한 커넥션 풀 크기를 유지하는 것이 실제 서비스에서 매우 중요한 포인트임을 배웠다.
🔸 기본값은 10이며, (CPU 코어 수 * 2) + 1 정도로 시작하는 것을 추천한다고 한다.
이전 과제에서 new 키워드로 직접 객체를 생성하던 방식은 확장성과 유지보수에 취약하다는 단점이 있었다. 이를 해결하기 위해 Spring은 다음과 같은 구조를 제공한다.
@Component, @Service, @Repository, @Controller 등을 통해 등록할 수 있다.아래와 같이 생성자 주입만 선언해두면, Spring이 알아서 Bean을 찾아 넣어준다.
@Service
public class PostService {
private final PostRepository postRepository;
public PostService(PostRepository postRepository) {
this.postRepository = postRepository;
}
}
이제는 의존 관계를 외부에서 관리하게 되므로, SOLID 원칙 중 DIP(의존성 역전 원칙) 도 자연스럽게 지킬 수 있다.
처음에는 단순히 try-catch를 쓰는 게 예외 처리라고 생각했다. 하지만 스프링 기반의 웹 서버는 다른 관점에서 예외를 처리해야 한다.
IllegalArgumentException 같은 예외를 throw 한다.@RestControllerAdvice를 통해 전역적으로 예외를 잡는다.ResponseEntity를 반환한다.@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse("400", e.getMessage()));
}
}
핵심은 예외를 처리하지 않으면 애플리케이션의 신뢰성이 떨어진다는 것이다.
이번 세미나에서 가장 인상 깊었던 개념은 관계(Relation) 의 의미였다.
🔑 "DB 설계는 단순 저장소 구성 이상이다. 결국 서비스 구조를 결정하는 뼈대이다."
워크벤치를 활용한 SQL 실습을 통해 다음 쿼리들을 직접 다뤄보았다.
CREATE TABLE, ALTER TABLE, DROP TABLEINSERT, SELECT, UPDATE, DELETE직접 SQL을 다루면서 느낀 건, JPA를 쓰더라도 SQL의 본질은 반드시 알고 있어야 한다는 점이다.
Java는 객체 지향 언어, DB는 관계형 시스템.
이 둘의 간극을 메워주는 것이 바로 ORM(Object-Relational Mapping) 이다.
"우리는 @Entity, @Id, @GeneratedValue 만 써도, DB와 객체 간의 변환을 거의 자동으로 처리할 수 있다."