Spring
🚀 이 주제를 선택한 이유 & 학습 목표
선택 배경: Spring 프레임 워크에 대해 놓친 부분 확인하기
학습 목표: Spring에 대해 다시 한번 복습하고, 정확한 구조 이해하기
📚 핵심 개념 및 원리
1. 주요 용어 정의
- DIP (Dependency Inversion Principle)
- 상위 모듈은 하위 모듈에 의존 X
- 추상화는 세부 사항에 의존 X
- SRP (Single Responsibility Principle)
- 각 클래스는 하나의 책임만 가져야한다.
- Aspect : 부가기능과 기능이 적용될 위치(Pointcut)을 합쳐 모듈화한 것
- Join Point : 프로그램 실행 중 특정시점, Spring AOP에서는 항상 메서드 실행을 뜻함
- Advice : Aspect가 특정 Join Point에서 수행하는 실제 비즈니스 로직
- Target : Advice를 받는 핵심 비즈니스 로직을 수행하는 객체
- Weaving : Aspect를 다른 애플리케이션 타입이나 객체에 연결하여 Advice를 적용된 객체를 만드는 과정
- CGLIB : 클래스 상속과 바이트 코드 조작으로 프록시 생성해주는 라이브러리
2. 핵심 원리/동작 방식
IoC (Inversion of Control)
객체의 생성, 생명주기 관리 등 제어권이 개발자가 아닌 프레임워크에게 넘어가는 것
Spring IoC 컨테이너
Bean을 관리하는 핵심 엔진
객체 생성 : 설정 메타 데이터 기반 Bean 객체 인스턴스화
DI (Dependency Injection) : Bean 객체 간의 의존 관계 자동 연결
- @Autowired : DI 자동 어노테이션
생명주기 관리
XML, 어노테이션 등 설정 기반 Bean 관리
BeanFactory VS ApplicationContext
- BeanFactory : IOC의 기본 형태, Bean 생성과 DI 기능 제공
- ApplicationContext : BeanFactory + 트랜잭션 관리, 이벤트 메커니증 등 추가 기능
Spring Bean
Spring IoC 컨테이너에 의해 생성되고, 관리되고, 의존성이 주입되는 객체
Bean 스코프 : 컨테이너가 Bean 인스턴스를 생성하고 관리하는 방식 결정
- singleton (default) : Spring IoC 컨테이너 내에서 단 하나의 인스턴스만 생성
- prototype : Bean을 요청할 때마다 새로운 인스턴스 생성
- request : 각 HTTP 요청마다 새로운 인스턴스 생성
- session : 각 HTTP 세션마다 새로운 인스턴스 생성
- application : ServletContext 생명주기와 동일하게 하나의 인스턴스 생성
AOP (Aspect-Oriented Programming)
OOP 과정에서 공통 부가 기능들을 핵심 비즈니스 로직으로부터 분리하여 별도의 모듈(Aspect)로 관리
Spring IoC를 보완
런타임에 프록시 객체 (기존 객체 + Aspect) 를 사용 -> JDK 동적 프록시 또는 CGLIB 라이브러리를 통해 생성
프록시 기반으로 메서드 실행 시점에만 부가 기능 적용
3. 관련 예시 또는 시나리오
- new 객체 생성 VS 생성자 주입
- new 사용
public class OrderService {
private PaymentService paymentService;
public OrderService() {
this.paymentService = new RealPaymentService(); // OrderService가 직접 RealPaymentService 객체를 생성
}
public void processOrder() {
// paymentService 사용
}
}- OrderService 클래스가 RealPaymentService라는 객체를 직접 생성하고 관리할 책임을 가짐
- PaymentService의 다른 구현체를 사용하려면 OrderService를 수정해야한다.
- 생성자 주입
@Service // OrderService도 Spring Bean으로 등록
public class OrderService {
private final PaymentService paymentService; // 인터페이스에 의존, final로 불변성 확보 가능
@Autowired // Spring 4.3 이후 생성자가 하나면 생략 가능[4][12]
public OrderService(PaymentService paymentService) { // 생성자를 통해 PaymentService 타입의 Bean을 주입받음
this.paymentService = paymentService;
}
public void processOrder() {
// paymentService 사용
}
}
// PaymentService 인터페이스
public interface PaymentService { /* ... */ }
@Component // RealPaymentService를 Spring Bean으로 등록
public class RealPaymentService implements PaymentService { /* ... */ }- 객체 생성의 책임은 Spring IoC 컨테이너
- 구현체가 아닌 인터페이스에 의존
결국 인터페이스에 의존하는 것은 동일하지 않나 ?
- DI의 목적은 결국 의존하는 클래스에서 구현체에 대한 의존을 끊는 것.
@Service // D 클래스도 Spring Bean
public class D {
private final A paymentProcessor; // A 인터페이스에만 의존
@Autowired
public D(A paymentProcessor) { // 외부에서 A 인터페이스의 구현체를 주입받음
this.paymentProcessor = paymentProcessor;
}
public void processPayment() {
paymentProcessor.pay();
}
}
// --- Spring 설정 부분 ---
// 방법 1: B를 기본 구현체로 사용
@Component
@Primary // B를 A 타입의 기본 Bean으로 지정
public class B implements A {
@Override
public void pay() {
System.out.println("B의 방식으로 결제");
}
}
@Component
public class C implements A {
@Override
public void pay() {
System.out.println("C의 방식으로 결제");
}
}- 동일 인터페이스의 다른 구현체로 교체 용이 -> 테스트 코드 작성 시 가짜 구현체 또한 사용가능
- 의존한 클래스가 아닌 구현체만을 변경하여 수정 가능
=> 객체의 응집도 향상, 결합도 낮추어 객체의 단일 책임 강화
🤔 나의 이해와 생각 정리 (회고)
핵심 요약: Spring 프레임워크의 모든 기능들의 지향점은 JAVA의 객체 지향성을 극대화하여 개발 효율성 향상이 목적으로 보인다.
새롭게 깨달은 점: 생각보다 용어나 개념에 대해서 정확히 정의내리지 못한 부분이 많았다. 안다고 생각했던 부분에 대해 미흡한 점을 많이 찾을 수 있었다.
더 궁금해진 점 / 의문점: 프레임워크 제작은 어떤식으로 이루어지는 것인가?
📖 더 학습할 내용 및 참고 자료
추가 학습 희망 분야: Spring Security, Filter, Intercept
✨ 마무리하며
앞으로도 모호했던 부분에 대한 지속적인 학습이 필요하다 느꼈다. 새로운 기술 이전에 기존의 사용하던 것들에 대한 지식에 대한 검증이 필요해 보인다.
'Study > CS' 카테고리의 다른 글
| 정렬 3편 (힙(Heap)과 힙 정렬) (2) | 2025.07.29 |
|---|---|
| 정렬 2편 (분할 정복: 병합 정렬, 퀵 정렬) (2) | 2025.07.29 |
| 정렬 1편 (버블 정렬, 선택 정렬, 삽입 정렬) (3) | 2025.07.29 |
| String과 StringBuilder (0) | 2025.06.27 |
| JVM (1) | 2025.05.26 |