스프링 컨테이너와 IoC, DI, Bean 1편

ILLION·2023년 3월 3일
0

Spring Framework

목록 보기
1/5
post-thumbnail

일단 먼저 공식적인 문서에 적인 정의를 말씀드리겠습니다.

1. 스프링 컨테이너(Spring Container)란

  • 스프링 컨테이너(Spring Container)는 IoC (Inversion of Control) 컨테이너와 DI (Dependency Injection) 컨테이너의 기능을 제공하는 핵심 컴포넌트
  • 스프링 컨테이너는 객체의 생성과 관리는 담당하는 IoC와 객체 간의 의존성을 관리하는 DI를 구현

2. IoC란

  • 제어의 역전이라는 뜻으로, 객체의 생성과 생명주기를 개발자가 아닌 프레임워크가 관리하는 것을 의미 즉! 즉프로그램의 제어 흐름을 개발자가 제어하는 것이 아닌, 외부에서 관리하는 것
  • 객체 간의 결합도를 낮추고 유연성과 재사용성을 향상시키는데 중요한 역할을 한다.

3. DI란

  • 의존성 주입이라는 뜻으로, 객체가 필요로 하는 의존성을 외부에서 주입받는 것을 의미 즉,
    객체가 필요로 하는 의존성을 직접 생성하지 않고 외부에서 주입받아 사용하는 것

이제부터 나름대로 이해한 내용을 말씀드리려합니다.

이해하기 위해서는 자바의 문법인 인터페이스, 생성자는 알고 있으셔야 이해하기 편하십니다.

4. IoC와 DI를 구현하지 않은 것과 한 것의 차이

일단 스프링 프레임워크는 스프링 컨테이너를 지원하는 프레임워크입니다.
스프링 컨테이너는 앞에 얘기했듯이 IoC와 DI를 지원하는 컨테이너이고요. 그럼 먼저 코드로
IoC와 DI를 구현하지 않은 코드 예시를 보여드리겠습니다.

public class ProductService {
// ProductRepository == 인터페이스이라고 가정
// ProductRepositoryImpl == ProductRepository인터페이스의 구현객체라고 가정
    private ProductRepository productDao = new ProductRepositoryImpl();

    public List<Product> 모든물건찾기() {
        return productDao.getAllProducts();
    }

    public void 물건등록하기(Product product) {
        productDao.addProduct(product);
    }

    public void 물건삭제하기(int productId) {
        productDao.deleteProduct(productId);
    }

    public void 물건수정하기(Product product) {
        productDao.updateProduct(product);
    }
}

위 코드에서 ProductService는 ProductRepository인터페이스에 의존하면서도 ProductRepositoryImpl라는 특정 구현객체에도 의존하고 있습니다. ProductService가 직접 객체를 생성하고 사용하기 때문에 추후 객체의 변경이 일어날 경우 유지보수에 어려움을 초래할 수 있습니다.

이번엔 프레임워크를 활용하지 않고 직접 IoC와 DI를 구현한 코드 보여드리겠습니다.

// 외부에서 의존성 주입을 하기 위한 클래스
public class AppConfig {

	public ProductService productService() {
    	return new ProductService(productRepository());
    }
    
    public ProductRepository productRepository() {
    	return new ProductRepositoryImpl(); // return되는 객체를 쉽게 변경가능
    }
    
}
public class Main {
    public static void main(String[] args) {
        // AppConfig 객체 생성
        AppConfig appConfig = new AppConfig();
        
        // ProductService 객체 생성, ProductDao 주입
        ProductService productService = appConfig.productService();
        
        // ProductService 사용  이번 내용과 무관!
        List<Product> products = productService.모든물건찾기();
        for (Product product : products) {
            System.out.println(product.getName());
        }
    }
}
public class ProductService {
    private ProductRepository productDao;

    public ProductService(ProductRepository productDao) { // 생성자를 통해 ProductRepository의 구현객체 주입
        this.productDao = productDao;
    }

    public List<Product> 모든물건찾기() {
        return productDao.getAllProducts();
    }

    public void 물건등록하기(Product product) {
        productDao.addProduct(product);
    }

    public void 물건삭제하기(int productId) {
        productDao.deleteProduct(productId);
    }

    public void 물건수정하기(Product product) {
        productDao.updateProduct(product);
    }
}

위 ProductService클래스는 생성자를 통해 ProductRepository인터페이스의 구현객체를 주입받도록 변경했습니다. ProductService클래스 내에서 직접 객체를 생성하지 않고,
AppConfig클래스(ProductService클래스 입장에선 AppConfig클래스가 외부)에서 주입받기 때문에 DI를 활용한 것이라고 할 수 있습니다.

그림으로 쉽게 보여드리겠습니다.

외부에서 객체를 주입함으로써 서비스로직은 추후 ProductRepository인터페이스의 구현객체가 다른것으로 바뀌더라도 오직 외부에서 주입받는 곳에서만 변경하면 되기에 유지보수에 용이합니다.

IoC와 DI를 구현하지 않을 땐 서비스객체가 직접 안에서 필요한 구현객체를 생성하고 실행했습니다. 즉 제어의 흐름을 스스로 제어했습니다. 하지만 AppConfig처럼 외부에서 제어의 흐름을 제어해주면서 ProductService클래스는 오직 자신의 로직만을 실행하는 것만 담당하고 있습니다.
이렇듯 프로그램 제어의 흐름을 직접 제어하는 것이 아닌 외부에서 제어하는 것을 제어의 역전(IoC)
라고 합니다.

마무리 and 다음 편엔?

지금까지 직접 구현한 Ioc와 DI를 활용한 것과 안한 것을 비교해봤습니다.
다음 편엔 스프링 프레임워크에서 지원하는 IoC와 DI를 어떻게 사용하는지, 내부 구성이 어떻게 흘러가는 지에 대해서 알아보겠습니다.
스프링 컨테이너와 IoC, DI, Bean 2편

profile
결과를 중요시하기보단 과정을 중요하게 생각하는 마음가짐

0개의 댓글