Dionysus

[개념] IOC 와 DI 본문

웹 개발/백엔드

[개념] IOC 와 DI

Gogumiing 2025. 6. 12. 15:01

 

 

< 목차 >

     

     


    💡 IoC (Inversion of Control) - 제어의 역전

    전통적인 프로그래밍에서는 개발자가 프로그램의 흐름과 제어를 직접 다루는 반면, IoC는 프레임워크가 객체의 생명주기, 관리, 제어 흐름을 담당하도록 변경하는 개념

     

    -> Spring은 이를 지원하기 위해 ApplicationContext라는 컨테이너를 제공한다.

     

    ✔️ ApplicationContext는 애플리케이션의 컴포넌트를 생성하고 조립하며, 객체의 라이프사이클을 관리한다.

     

     

    🍃 ApplicationContext의 동작 과정은 아래와 같다.

    1. 객체의 생성 및 관리
      • ApplicationContext를 사용하여 빈(Bean)을 생성 및 관리
      • 빈(Bean)은 일반적으로 Spring이 제어하며, 개발자는 객체의 생성과 관리를 직접 처리하지 않음
    2. 의존성 관리
      • 객체 간의 의존성을 Spring이 주입(DI, Dependency Injection)
      • 객체가 필요로 하는 다른 객체를 직접 생성하거나 찾는 대신, Spring 컨테이너가 의존성을 주입해줌
    3. 제어 흐름의 역전
      • 개발자가 코드의 제어 흐름을 결정하지 않고, 프레임워크(Spring)가 객체의 라이프사이클 및 실행 흐름을 관리함

    💡 DI (Dependency Injection, 의존성 주입)

    객체 간의 의존성을 프레임워크가 주입하는 개념으로, 객체가 직접 의존하는 객체를 생성하거나 참조하는 대신 의존성을 외부에서 주입받도록 하는 것을 의미

     

    -> Spring은 다양한 방법으로 DI를 지원한다.

     

    ✔️ DI를 사용하지 않는다면,

    public class OrderServiceImpl implements OrderService {
        private MemberRepository memberRepository;
    
        public OrderService() {
            this.MemberRepository = new MemberRepository();
        }
    
        // ...
    }

     

    예시 코드에서 OrderServiceImpl는 직접적으로 MemberRepository를 생성하고 의존하므로, 강한 결합이 생성된다. 이로 인해 유지 보수성이 떨어진다. 그렇다면 DI를 사용하면 어떻게 될까?

     

    ✔️ DI (의존 관계 주입) 방법

    1. 생성자 주입 - 생성자를 통해 의존성 주입
    2. 수정자 주입 - Setter 메서드를 통해 의존성 주입
    3. 필드 주입 - 필드에 직접 의존성 주입
    4. 일반 메서드 주입 - 메서드의 매개변수로 의존성 주입

     

    참고로, 의존관계 자동 주입(@Autowired)은 스프링 컨테이너가 관리하는 스프링 빈(@Component/@Controller/@Service/@Configuration)이어야 동작한다.

     

     

     

    🍃 1. 생성자 주입 - 생성자를 통해 의존성 주입

    • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장됨
    • 불변, 필수 의존 관계에 사용
    @Component
    public class OrderServiceImpl implements OrderService {
    
        private final MemberRepository memberRepository;
        private final DiscountPolicy discountPolicy;
    
        @Autowired
        public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy){
            this.memberRepository = memberRepository;
            this.discountPolicy = discountPolicy;
        }
    }

     

    -> 참고로 아래 코드와 같이 스프링 빈에 한하여, 생성자가 딱 1개만 있으면 @Autowired를 생략해도 의존성은 자동 주입된다.

    @Component
    public class OrderServiceImpl implements OrderService {
    
        private final MemberRepository memberRepository;
        private final DiscountPolicy discountPolicy;
    
        public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
            this.memberRepository = memberRepository;
            this.discountPolicy = discountPolicy;
        }
    }

     

     

    🍃 2. 수정자 주입 - Setter 메서드를 통해 의존성 주입

    • setter라 불리는 필드의 값을 변경하는 수정자 메서드를 통해 의존관계를 주입하는 방법
    • 선택, 변경 가능성이 있는 의존 관계에 사용
    • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법
    @Component
    public class OrderServiceImpl implements OrderService {
    
        private MemberRepository memberRepository;
        private DiscountPolicy discountPolicy;
    
        @Autowired
        public void setMemberRepository(MemberRepository memberRepository) {
            this.memberRepository = memberRepository;
        }
    
        @Autowired
        public void setDiscountPolicy(DiscountPolicy discountPolicy) {
            this.discountPolicy = discountPolicy;
        }
    }

     

     

    🍃 3. 필드 주입 - 필드에 직접 의존성 주입

    • 필드에 바로 주입하는 방법
    • 코드가 간결하단 장점이 있지만, 외부에서 변경이 불가능해 테스트하기 힘들다는 아주 치명적인 단점을 가짐
    • DI 프레임워크가 없으면 아무것도 할 수 없음
    • 스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 사용할 것을 권장함
    @Component
    public class OrderServiceImpl implements OrderService {
    
        @Autowired
        private MemberRepository memberRepository;
    
        @Autowired
        private DiscountPolicy discountPolicy;
    
    }

     

     

    🍃 4. 일반 메서드 주입 - 메서드의 매개변수로 의존성 주입

    • 일반 메서드를 통해 주입
    • ‼️일반적으로 잘 사용하지 않음
    @Component
    public class OrderServiceImpl implements OrderService {
        private MemberRepository memberRepository;
        private DiscountPolicy discountPolicy;
    
        @Autowired
        public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){
            this.memberRepository = memberRepository;
            this.discountPolicy = discountPolicy;
        }
    
    }

    '웹 개발 > 백엔드' 카테고리의 다른 글

    [개념] 최대 유휴 시간(MIT)과 최대 유지 시간(ML)  (0) 2025.06.20
    [개념] AOP  (0) 2025.06.16
    [개념] GenericDAO  (0) 2025.06.06