HJW's IT Blog

[SPRING BOOT] IOC, DC, BEAN 에 대해 본문

SPRING

[SPRING BOOT] IOC, DC, BEAN 에 대해

kiki1875 2024. 5. 28. 13:21

IOC : Inversion of Control

IOC는 객체 생성 / 객체 사이의 의존성 관리를 개발자가 직접 제어하는 것이 아닌 컨테이너 혹은 프레임워크에 맡기는 것을 의미한다. 이를 통해 객체 간의 결합도를 낮출 수 있다.

전통적인 프로그래밍 방식은 객체를 직접 생성하고 의존성을 관리해주어야 한다. 예를 들어 A 객체가 B 객체를 사용한다면 A 객체 내에서 B 객체를 생성해야 한다. 하지만 IOC 를 사용하면,

  • 클래스 내부의 객체 생성 → 의존성 객체의 메소드 호출 이 아닌 스프링에게 제어를 위임하여 스프링이 만듣 객체를 주입 → 의존성 객체의 매소드 호출 구조이다.

DI : Dependency Injection

IOC 패턴의 일종으로, 객체 간의 의존성을 외부에서 주입하는 방식으로, 생성자, setter 메서드, 또는 필드에 주입이 있다.

예를 들어, A 객체가 B 객체를 사용한다면 A 객체 내부에서 B 객체를 생성하지 않고, 외부에서 생성된 B 객체를 주입받는다. 이렇게 하면 A 객체는 B 객체의 구현 방식에 대해 알 필요가 없으므로 객체 간의 결합도가 낮아진다.

  • 어떠한 객체 B 를 사용한느 주체(A) 가 객체 B 를 직접 생성하는 것이 아닌 외부에서 생성하여 사용하려는 객체 A 에 주입하는 방식
  • A 에서 객체를 직접 생성할 경우, 의존성이 높아진다 → DI 를 통해 외부에서 생성, 외부에서 관리하는 구조로 의존성이 낮아진다

다음은 DI의 3가지 주입 방식이다.

  1. 생성자 주입 →
public class CustomerService {
    private final CustomerRepository customerRepository;

    public CustomerService(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    // CustomerService 로직
}
  1. Setter 주입
public class CustomerService {
    private CustomerRepository customerRepository;

    public void setCustomerRepository(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    // CustomerService 로직
}
  1. 필드 주입
public class CustomerService {
    @Autowired
    private CustomerRepository customerRepository;

    // CustomerService 로직
}

Bean

DI 컨테이너가 관리하는 개체로, @Component 등의 어노테이션을 사용하여 Bean 을 정의한다. 스프링 컨테이너는 Bean 을 생성, 관리하며, 필요한 의존성을 주입한다.

  • Spring IOC 컨테이너가 관리하는 자바 객체
  • POJO(Plain Old Java Object) 기반
  • 특징
    • 의존성 주입 → 스프링은 Bean 간의 의존관계를 자동으로 구성. 이를 통해 객체간의 결합도 를 낮춘다
    • 생명 주기 관리 : 스프링 컨테이너는 Bean 의 완전한 생명주기를 관리 (초기화, 소멸 콜백 등등)
    • 범위 → Bean 의 범위는 싱글톤, 프로토타입, 요청, 세션 등이 있다.
    • Bean 자동 검색 → annotation 을 사용하여 Bean 을 자동을 ㅗ검색, 의존성을 주입할 수 있다 (@Component, @Autowired)

스프링에서 빈을 등록하는 방식은 크게 명시적 빈 등록 자동 빈 등록 두가지로 나눌 수 있다.

  • 명시적 등록 → 개발자가 직접 빈을 정의하고 등록하는 방식
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public CustomerService customerService(CustomerRepository customerRepository) {
        return new CustomerService(customerRepository);
    }

    @Bean
    public CustomerRepository customerRepository() {
        return new CustomerRepository();
    }
}
  • 자동 등록 → 어노테이션을 사용하여 스프링 컨테이너가 자동으로 빈을 등록하는 방식. @Component, @Service, @Repository 등이 있다.
import org.springframework.stereotype.Service;

@Service
public class CustomerService {
    // ...
}

왜 이런 패턴을 사용하는가?

  1. 낮은 결합도 : 객체간의 결합도가 낮아져 유지 보수성 및 확장성의 증가
  2. 재사용성 증가 : 객체를 모듈화 하여 재사용성을 높일 수 있다
  3. 단위 테스트 용이 : 객체간의 의존성을 Mock 객체로 대체할 수 있어 단위 테스트가 용이
  4. 객체 수명주기 관리 : 스프링 컨테이너가 객체의 생성, 초기화, 소멸 등의 수명 주기를 관리해준다