TIL - 20251107

juni·2025년 11월 7일

TIL

목록 보기
171/317

1107 Spring Boot의 핵심 원리: DI, IoC, AOP


✅ 1. 제어의 역전 (IoC - Inversion of Control)

  • IoC(제어의 역전)는 Spring 프레임워크의 가장 근본적인 설계 원리입니다.

  • 전통적인 방식: 개발자가 직접 객체를 생성하고, 의존성을 연결하며 프로그램의 흐름을 제어합니다.

    public class MyController {
        // 개발자가 직접 서비스 객체를 생성 (제어권이 개발자에게 있음)
        private MyService myService = new MyService();
    }
  • IoC 방식: 객체의 생성과 생명주기 관리, 의존성 연결 등 모든 제어권이 개발자로부터 프레임워크(Spring 컨테이너)로 넘어간(역전된) 것을 의미합니다.

    • 개발자는 어떤 객체가 필요하고, 어떻게 동작해야 하는지만 정의하면, Spring이 알아서 객체를 만들고, 필요한 곳에 연결해주며, 전체 프로그램의 흐름을 관리합니다.

✅ 2. 의존성 주입 (DI - Dependency Injection)

  • DI(의존성 주입)IoC를 구현하는 구체적인 방법 중 하나입니다.

  • 개념: 클래스가 의존하는(필요로 하는) 다른 객체를 내부에서 직접 생성하는 것이 아니라, 외부(Spring 컨테이너)에서 생성하여 주입(Injection)받는 방식입니다.

  • 왜 사용하는가? (DI의 장점)

    1. 느슨한 결합 (Loose Coupling): 클래스들이 구체적인 구현 클래스가 아닌, 인터페이스에만 의존하게 됩니다. (SOLID의 DIP 원칙)
    2. 유연성 및 확장성: 의존하는 객체의 구현이 변경되더라도, 해당 객체를 사용하는 코드는 전혀 수정할 필요가 없습니다. (SOLID의 OCP 원칙)
    3. 테스트 용이성: 실제 객체 대신 가짜(Mock) 객체를 쉽게 주입하여 단위 테스트를 수행하기 매우 용이해집니다.

➕ Spring의 3가지 의존성 주입 방법

  1. 생성자 주입 (Constructor Injection) - 가장 권장되는 방법

    • 생성자를 통해 의존성을 주입받습니다.
    • 장점:
      • 불변성(Immutability) 보장: final 키워드를 사용할 수 있어, 객체가 생성된 후 의존성이 변경될 위험이 없습니다.
      • 의존성 누락 방지: 객체 생성 시점에 모든 의존성이 반드시 주입되어야 하므로, NullPointerException(NPE)을 원천적으로 방지할 수 있습니다.
      • 순환 참조 방지: 생성자 주입은 순환 참조 발생 시 애플리케이션 시작 시점에 오류를 발생시켜 문제를 조기에 발견할 수 있습니다.
    @Service
    public class MyService {
        private final MyRepository myRepository;
    
        // 생성자가 하나만 있을 경우 @Autowired 생략 가능
        public MyService(MyRepository myRepository) {
            this.myRepository = myRepository;
        }
    }
  2. 필드 주입 (Field Injection)

    • 필드(멤버 변수)에 @Autowired를 직접 붙여 주입합니다.
    • 단점: 코드가 간결해 보이지만, 외부에서 의존성을 주입할 방법이 없어 테스트가 어렵고, 순환 참조를 발견하기 어려워 사용이 권장되지 않습니다.
  3. 수정자 주입 (Setter Injection)

    • Setter 메서드를 통해 의존성을 주입합니다.
    • 단점: 객체가 생성된 후에도 의존성을 변경할 수 있어 불변성을 해치고, 의존성 주입이 선택적이라 NullPointerException이 발생할 수 있습니다.

✅ 3. Spring 컨테이너와 Bean

  • Spring 컨테이너 (IoC 컨테이너, DI 컨테이너):

    • Spring의 핵심 엔진으로, Bean의 생명주기를 관리하고, 의존성을 주입해주는 역할을 합니다.
    • 대표적인 구현체로 ApplicationContext가 있습니다.
  • Bean:

    • Spring 컨테이너가 관리하는 객체를 의미합니다.
    • 개발자는 @Component 어노테이션(또는 이를 포함하는 @Service, @Repository, @Controller 등)을 클래스에 붙여, 해당 클래스의 객체를 Bean으로 등록해달라고 Spring에 요청합니다.
    • Spring은 시작 시점에 이 어노테이션들을 스캔하여 Bean 객체들을 생성하고 컨테이너에 보관합니다.

✅ 4. 관점 지향 프로그래밍 (AOP - Aspect-Oriented Programming)

  • AOP는 OOP를 보완하는 프로그래밍 패러다임입니다.

  • 문제점 (횡단 관심사의 분리): 애플리케이션의 여러 비즈니스 로직(핵심 관심사)에 걸쳐 공통적으로 나타나는 부가 기능(e.g., 로깅, 트랜잭션, 보안)들이 있습니다. OOP만으로는 이러한 "횡단 관심사(Cross-cutting Concerns)"를 분리하기 어려워, 모든 비즈니스 메서드에 중복된 코드가 흩어지게 됩니다.

  • AOP의 해결책: 횡단 관심사를 "Aspect"라는 별도의 모듈로 분리하여, 핵심 비즈니스 로직에는 영향을 주지 않으면서 필요한 곳에 동적으로 적용(Weaving)하는 방식입니다.

➕ AOP의 주요 용어

  • Aspect: 횡단 관심사를 모듈화한 것. (e.g., LoggingAspect)

  • Advice: Aspect가 실제로 수행하는 부가 기능 로직. (e.g., "메서드 시작 전에 로그를 남긴다.")

    • @Before, @After, @Around
  • Pointcut: Advice를 어디에 적용할지 결정하는 표현식. (e.g., "모든 서비스 계층의 create로 시작하는 메서드에 적용")

  • Join Point: Advice가 적용될 수 있는 모든 위치. (e.g., 메서드 호출, 필드 값 변경 등)

  • Spring의 @Transactional: Spring AOP의 가장 대표적인 활용 사례입니다. 개발자는 비즈니스 로직에만 집중하고, @Transactional 어노테이션만 붙이면, Spring이 AOP를 통해 해당 메서드의 시작과 끝에 트랜잭션 시작/커밋/롤백이라는 부가 기능(Aspect)을 동적으로 적용해줍니다.


📌 요약

  • IoC(제어의 역전)는 객체 관리의 제어권이 개발자에서 프레임워크로 넘어간 설계 원리입니다.
  • DI(의존성 주입)는 IoC를 구현하는 방식으로, 필요한 객체를 외부(Spring 컨테이너)에서 주입받아 클래스 간의 결합도를 낮춥니다. 이 중 생성자 주입이 가장 권장됩니다.
  • Spring 컨테이너Bean의 생명주기를 관리하고 DI를 수행하는 핵심 엔진입니다.
  • AOP(관점 지향 프로그래밍)는 로깅, 트랜잭션과 같은 횡단 관심사(부가 기능)Aspect로 모듈화하여, 핵심 비즈니스 로직의 순수성을 유지하고 코드 중복을 제거하는 강력한 기술입니다.

0개의 댓글