Spring과 Spring Boot의 차이
설정 방식
Spring은 XML이나 Java Config를 통해 세밀한 설정이 필요하지만
Spring Boot는 자동 설정 기능을 제공해 초기 설정이 간단합니다.
배포 방식
Spring은 외부 WAS에서 실행해야 하는 WAR 파일로 배포하는 경우가 많고
Spring Boot는 내장 서버를 포함한 JAR 파일로 독립 실행이 가능합니다.
의존성 관리
Spring에서는 개발자가 필요한 라이브러리를 수동으로 관리해야 하지만
Spring Boot는 Starter 의존성을 제공해 쉽게 통합할 수 있습니다.
목적
Spring은 유연성과 세밀한 제어에 초점이 맞춰져 있고
Spring Boot는 빠른 개발과 생산성 향상을 목적으로 설계되었습니다.
이렇게 Spring Boot는 Spring의 복잡함을 줄이고 더 빠르고 간편한 애플리케이션 개발을 돕습니다.
Spring Framework의 특징
IoC(Inversion of Control)
객체의 생성 및 생명 주기를 개발자가 아닌 컨테이너(Spring Container)가 관리합니다.
이를 통해 의존성 주입(Dependency Injection)을 구현합니다.
AOP(Aspect-Oriented Programming)
비즈니스 로직과 공통 관심사(로깅, 보안 등)를 분리해 코드 재사용성과 유지보수성을 높입니다.
MVC 구조 지원
Spring MVC를 통해 모델-뷰-컨트롤러 아키텍처를 쉽게 구현할 수 있습니다.
모듈화
Spring Core, Spring MVC, Spring Data 등 독립적인 모듈로 구성되어 필요에 따라 선택적으로 사용할 수 있습니다.
테스트 용이성
DI를 통해 객체 간 결합도를 낮추고, 단위 테스트와 통합 테스트를 쉽게 작성할 수 있습니다.
경량 프레임워크
EJB와 달리 가볍고 빠르며 Java SE와 EE 모두에서 사용할 수 있습니다.
Spring Framework는 유연성과 확장성을 바탕으로 다양한 애플리케이션 개발에 적합합니다.
Ioc / DI
IoC는 객체의 생성과 생명 주기를 개발자가 아닌 컨테이너가 관리하는 큰 개념이고
DI는 IoC를 구현하는 방법 중 하나로 객체의 의존성을 외부에서 주입하는 방식이다.
DI는 객체 간 결합도를 낮추고 IoC는 전체 제어 흐름을 관리합니다.
생성자 주입을 사용하는 이유
불변성 보장
의존성이 생성 시에만 설정되어 이후 변경되지 않아 객체의 불변성을 유지합니다.
필수 의존성 명시
생성자를 통해 필수 의존성을 강제할 수 있어 의존성 누락을 방지합니다.
테스트 용이성
생성자를 통해 Mock 객체를 쉽게 주입할 수 있어 단위 테스트가 간편해집니다.
순환 의존 방지
순환 의존성을 컴파일 시점에 확인할 수 있어 안정성을 높입니다.
Spring Bean
Spring IoC 컨테이너가 관리하는 객체를 말합니다.
생성과 관리
객체의 생성, 초기화, 소멸 등 생명 주기를 컨테이너가 관리합니다.
등록 방법
@Component, @Service, @Repository 같은 어노테이션을 등록하거나
@Bean을 사용해 수동 등록합니다.
특징
기본적으로 Singleton으로 관리되며 필요하면 Scope를 변경할 수 있습니다.
역할
의존성 주입(DI)을 통해 Bean 간 관계를 설정해 결합도를 낮추고 재사용성을 높입니다.
간단히 말해 Spring Bean은 컨테이너가 관리하며 애플리케이션 전반에서 객체를 효율적으로 재사용하도록 돕는 핵심 요소입니다.
Spring Bean의 Scope
Bean이 생성되고 관리되는 범위를 지정하는 설정입니다.
Spring에서 제공하는 주요 Scope는 다음과 같습니다.
- Singletion(기본값)
- 컨테이너당 하나의 Bean 인스터스만 생성됩니다.
- 애플리케이션 전역에서 같은 객체를 공유합니다.
- Prototype
- 요청마다 새로운 Bean 인스턴스를 생성합니다.
- 상태를 가지는 객체나 특정 작업에만 필요한 경우에 사용합니다.
- Request(웹 애플리케이션)
- HTTP 요청당 하나의 Bean 인스턴스를 생성하고 요청이 끝나면 소멸합니다.
- Session(웹 애플리케이션)
- HTTP 세션당 하나의 Bean 인스턴스를 생성합니다.
- Applicaiton(웹 애플리케이션)
- 서블릿 컨텍스트(Application Context)당 하나의 Bean 인스턴스를 생성합니다.
- WebSocket
- WebSocket 세션당 하나의 Bean 인스턴스를 생성합니다.
@Component / @Bean
공통점
- 둘 다 Spring 컨테이너에 관리되는 Bean을 등록합니다.
- 등록된 Bean은 의존성 주입을 통해 사용할 수 있습니다.
차이점
- 사용 방식과 목적에서 차이가 있습니다.
- @Component
- 클래스에 선언해 자동으로 Bean 등록을 처리합니다.
- Spring이 제공하는 기본 방식으로, 주요 로직 클래스에서 사용됩니다.
- 서비스나 레포지토리 같은 역할의 클래스를 등록할 때 사용합니다.
- @Bean
- 메서드에 선언해 수동으로 Bean 등록을 처리합니다.
- 외부 라이브러리를 Bean으로 등록하거나, Bean 생성 로직을 세부적으로 제어할 때 사용됩니다.
- 주로 @Configuration 클래스 내부에서 사용됩니다.
- @Component
@Component는 간단하고 자동화된 방식, @Bean은 세부 제어가 필요한 경우 사용하는 방식입니다.
AOP(Aspect-Oriented Programming)
관점 지향 프로그래밍으로 핵심 비즈니스 로직과 공통 관심사(로깅, 보안, 트랜잭션)를 분리해
코드의 재사용성과 유지보수성을 프로그래밍 방식입니다.
Spring에서는 주로 프록시를 이용해 메서드 실행 시점에 공통 로직을 적용합니다.
CORS(Cross-Origin Resource Sharing)
다른 도메인 간 리소스 공유를 허용하기 위한 보안 정책입니다.
브라우저는 보안상의 이유로 기본적인 다른 도메인에서의 요청을 차단합니다.
CORS는 서버에서 적절한 HTTP 헤더를 설정하여 특정 도메인에서의 요청을 허용하도록 합니다.
Spring에서 CORS 문제를 해결하려면 클라이언트의 요청을 서버에서 허용하도록 설정해야 합니다.
특정 컨트롤러나 메서드에서 허용할 수 있고 애플리케이션 전역에서 CORS 설정을 적용할 수도 있습니다.
Spring Security 사용 시 CORS 설정을 추가해야 합니다.
Spring MVC
Model-View-Controller 아키텍처를 기반으로 웹 애플리케이션을 개발하기 위한
Spring의 웹 프레임워크입니다.
처리 과정
사용자가 브라우저에서 특정 URL을 요청합니다.
⬇️
Spring의 DispatcherServlet이 모든 요청을 가로채고 컨트롤러로 전달할 준비를 합니다.
⬇️
DispatcherServlet은 요청 URL을 분석하여 적합한 Controller를 찾습니다.
⬇️
요청을 처리할 로직을 수행하고 Model에 데이터를 담아 적합한 View 이름을 반환합니다.
⬇️
반환된 View 이름을 기반으로 ViewResolver가 실제 View 파일 경로를 찾습니다.
⬇️
ViewResolver가 지정한 파일을 렌더링하여 사용자에게 응답합니다.
⬇️
최종 HTML이 사용자 브라우저로 전송됩니다.
@RequestParam / @RequestBody / @ModelAttribute
모두 요청 데이터를 컨트롤러로 전달받는 방법입니다.
@RequestParam
- 쿼리 스트링이나 폼 데이터에서 값을 가져옵니다.
- ex. name=John&age=25 >> 단일 값 매핑
@RequestBody
- 요청의 HTTP Body에 담긴 JSON이나 XML 데이터를 객체로 변환합니다.
- {"name" : "John", "age" : 25} >> 객체 매핑
@ModelAttribute
- 요청 파라미터를 객체로 바인딩하거나 View로 데이터를 전달할 때 사용합니다.
- 주로 폼 데이터 처리에 활용합니다.
정리하자면 단순 파라미터는 @RequestParam, JSON 요청은 @RequestBody, 폼 데이터는 @ModelAttribute를 사용합니다.
VO / DTO / DAO
애플리케이션에서 데이터를 처리하는 데 사용되는 객체의 종류입니다.
VO(Value Object)
- 값을 표현하는 객체로 주로 읽기 전용입니다.
- 불변성을 보장하며, 값 자체를 비교하는 데 사용됩니다.
DTO(Data Transfer Object)
- 데이터를 계층 간 전달하기 위한 객체입니다.
- 주로 컨트롤러와 서비스 계층 간 데이터를 전달할 때 사용됩니다.
DAO(Data Access Object)
- 데이터베이스와의 상호작용을 담당하는 객체입니다.
- CRUD 작업을 처리합니다.
- 보통 Repository 패턴으로 구현됩니다.
JPA / MyBatis
데이터베이스와 상호작용하기 위한 Java 기술로 접근 방식에 차이가 있습니다.
JPA(Java Persistence API)
- ORM 기술로 객체와 데이터베이스 테이블 간 매핑을 자동으로 처리합니다.
- SQL 대신 JPQL이라는 객체 중심 쿼리 언어를 사용합니다.
- 자동 매핑과 지연 로딩 같은 기능으로 개발 생산성을 높입니다.
- 하지만 복잡한 쿼리 작성은 어렵습니다.
MyBatis
- SQL 매퍼로 SQL을 직접 작성하여 데이터베이스와 상호작용합니다.
- XML 또는 어노테이션으로 매핑을 정의합니다.
- 복잡한 쿼리를 처리하기 쉽고, SQL 최적화를 세밀하게 조정할 수 있습니다.
- SQL 작성량이 많아질수록 유지보수가 어려워질 수 있습니다.
Entity
JPA에서 데이터베이스와 Java 객체를 연결하는 핵심 구성 요소로
데이터의 구조와 테이블의 스키마를 정의합니다.
@Entity와 @Id는 필수이며 데이터베이스의 칼럼은 클래스의 필드로 표현합니다.
자동 생성, 관계 설정(1:1, 1:N, N:M) 등 다양한 매핑 기능을 제공합니다.
영속성 컨텍스트
JPA에서 Entity를 관리하는 메모리 공간입니다.
데이터베이스와의 직접적인 상호작용을 최소화하고 애플리케이션 내에서 사용하는 Entity 객체를 캐싱하여 효율성을 높입니다. 이를 통해 동일한 트랜잭션 내에서는 동일한 객체를 반환하며, 1차 캐시를 통해 데이터베이스 접근을 줄이고 성능을 최적화합니다. 지연 로딩 기능을 제공해 실제로 필요한 데이터만 로드하여 최적화를 돕습니다.
어노테이션
어노테이션을 통해 구성, 의존성 주입, 트랜잭션 관리 등을 선언적으로 처리할 수 있습니다.
트랜잭션
데이터베이스에서 하나의 작업 단위를 의미하며 작업이 모두 성공하거나 모두 실패하도록 보장하는 메커니즘입니다. 데이터 일관성을 유지하기 위해 원자성, 일관성, 고립성, 지속성을 제공합니다.
Spring에서는 @Transactional 어노테이션을 통해 트랜잭션을 선언적으로 관리하며 예외 발생 시 자동으로 Rollback하고 성공하면 Commit하여 작업을 확정합니다. 이를 통해 데이터 무결성과 안정성을 보장합니다.
즉시 로딩(Eager Loading) / 지연 로딩(Lazy Loading)
JPA에서 연관된 엔티티를 조회하는 방식입니다.
즉시 로딩
- 쿼리가 실행될 때 연관된 엔티티까지 모두 조회합니다.
- @OneToOne, @ManyToOne은 기본적으로 즉시 로딩입니다.
- 초기 데이터를 모두 로드하기 때문에 한 번의 요청에 필요한 데이터가 많을 때 유리하지만 불필요한 데이터를 로딩할 위험이 있습니다.
지연 로딩
- 연관된 엔티티를 필요할 때 로딩합니다.
- @OneToMany, @ManyToMany는 기본적으로 지연 로딩입니다.
- 처음에는 프록시 객체만 로드하고 연관 엔티티가 실제로 필요할 때 조회합니다.
- 데이터 양이 많거나 초기화 비용을 줄이고 싶을 때 유리하지만 잘못 사용하면 N+1 문제를 발생시킬 수 있습니다.
N+1 문제
JPA에서 지연 로딩을 사용할 때 발생하는 성능 문제입니다.
한 번의 조회로 여러 개의 데이터를 가져오려는 상황에서 연관된 엔티티를 개별적으로 조회하기 때문에 총 N번의 추가 쿼리가 발생하게 됩니다.
해결 방법
JPQL에서 명시적으로 JOIN FETCH를 사용해 연관 데이터를 한 번에 조회하거나
@EntityGraph를 사용해서 연관된 엔티티를 즉시 로딩으로 설정합니다.
'공부 > Spring Framework' 카테고리의 다른 글
🔍 HS512 알고리즘 (3) | 2024.11.15 |
---|