관리 메뉴

Rootable의 개발일기

Dependency Injection(DI)과 IoC(Inversion of Control) 본문

Spring

Dependency Injection(DI)과 IoC(Inversion of Control)

dev-rootable 2023. 4. 27. 20:55

일반적으로 스프링을 공부하기 전에는 모든 class 에서 필요한 객체가 있으면 new 를 해서 생성 후 사용했다.

 

public class MemberController {

	MemberService memberService = new MemberService;
	...
}

Service 가 수행하는 기능은 프로젝트의 도메인 단위로 관련된 Controller 나 Repository 에서 공용으로 사용되는 경우가 일반적이다. 그런데, Service 를 매번 new 를 해서 생성하게 되면 2가지 문제점이 발생한다.

 

1. 두 클래스가 강하게 결합되는 문제

두 클래스가 강하게 결합될 경우, 다른 클래스로 교체해야 하는 상황이 발생한다면 생성자를 고쳐야 하거나 해당 객체를 

사용하는 모든 소스 코드를 수정해야 한다. 즉 유연성이 떨어진다. 이를 위해 생성자만 다르고, 나머지는 중복되는 코드를

가진 클래스를 파생하는 것도 좋지 못하다. 그리고 이에 대한 해결책으로 상속을 생각할 수 있지만, 상속은 제약 사항이 

많고 확장성이 떨어지므로 피하는 것이 좋다.

 

2. 객체들 간의 관계가 아니라 클래스들 간의 관계가 맺어지는 문제

올바른 객체지향적 설계라면 클래스가 아닌 객체들 간의 관계가 맺어져야 한다. 객체들 간의 관계가 맺어졌다면 다른 객체의 구현 클래스를 전혀 알지 못하더라도,
(해당 인터페이스를 구현한 클래스라면) 인터페이스 타입으로 사용할 수 있어 클래스 간에 의존하지 않도록 작성할 수 있다.

 

📌 Spring Container(=DI Container = IoC Container)

@Controller
public class Shop {
	
    private final Product product;
    
    /*
    * Product : interface
    * 생성자에 @Autowired 가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어줌
    */
    @Autowired
    public Shop(Product product) { //Shop 클래스는 어떤 구현 클래스가 오는지 몰라도 됨
    	this.product = product;
    }
}

 

위 코드는 Shop 에서 어떤 상품을 판매할지라는 관심사가 분리되었다.

 

위 코드처럼 작성해야 Shop 클래스가 구현 클래스에 의존하지 않게 된다. 이를 위해서 스프링 컨테이너에 객체(빈)을 등록하여 스프링 컨테이너에 의해 관리되도록 해야 한다. 이렇게 하면 스프링 컨테이너가 애플리케이션 실행 시점에 필요한 객체(Bean) 을 생성하여 의존성이 있는 두 객체를 연결하기 위해 한 객체를 다른 객체에 주입시킨다.

 

이처럼 스프링은 클래스를 탐색하고, 객체를 만들어 객체들의 관계도 맺어준다. 그리고 이러한 개념은 제어의 역전(Inversion of Control, IoC) 라고도 불린다. 어떠한 객체를 사용할지에 대한 책임은 프레임워크에 넘어갔고, 자신은 주입 받는 객체를 사용하기 때문이다.

 

위처럼 외부에서 필요한 객체를 생성하고 관리하면서 객체들 사이의 의존관계를 연결해 주는 것을

Spring Container(=Object Factory = Assembler) 라고 부른다.

 

📌 정리

 

한 객체가 어떤 객체(구현 클래스)에 의존할 것인지는 별도의 관심사다. Spring 은 의존성 주입을 도와주는 Spring Container로서 결합도를 낮추고 유연성을 확보한다. 따라서, 애플리케이션 실행 시점에 두 클래스의 관계를 결정하여 객체지향적인 코드를 작성하고 확장성을 높이도록 하기 위해 DI 가 필요하다.

단, 이를 위해서 스프링 컨테이너에 해당 객체가 등록되어 있어야 한다.

  • 두 클래스 간의 관계라는 관심사의 분리
  • 두 객체 간의 결합도를 낮춤
  • 객체의 유연성을 높임
  • 테스트 작성을 용이하게 함

하지만 의존 관계를 주입할 객체를 계속해서 생성하고 소멸한다면, 아무리 GC가 성능이 좋아졌다고 하더라도 부담이 된다. 그래서 Spring에서는 Bean들을 기본적으로
싱글톤
으로 관리한다.

 

기본적으로 웹은 한 번에 많은 사용자 요청이 들어온다. 이 때, 싱글톤 패턴이 아니면 고객 트래픽만큼 객체가 생성되고 소멸되기 때문에 메모리 낭비가 심할 수 밖에 없다.

 

싱글톤 : 유일하게 하나만 등록해서 공유하는 형태 (같은 스프링 빈이면 모두 같은 인스턴스)

 

📌 IoC

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    public DiscountPolicy discountPolicy() {
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();
    }

}

 

의존성 주입(DI) 효과를 내기 위해 만든 AppConfig는 객체를 생성하는 동시에 필요한 의존 객체를 생성하여 생성자 매개변수로서 주입한다. 결과적으로
프로그램 제어 흐름에 대한 권한을 모두 AppConfig라는 설정 파일이 가지고 있는 것이다. 이처럼 프로그램(ex.OrderServiceImpl)의 제어 흐름을
직접 제어하는 것이 아니라 외부(AppConfig)에서 관리하는 것
제어의 역전(IoC)이라고 한다.

 

📌 의존 관계

 

🔎 정적인 클래스 의존 관계

 

클래스가 사용하는 import 코드만 봐도 알 수 있는 의존 관계로 new 를 통해 의존성 객체를 명시하기 때문에 코드를 실행하지 않아도 의존 관계를 파악할 수 있다.

 

🔎 동적인 객체 인스턴스 의존 관계 (=DI Container)

 

애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계다. 따라서, 실행 시점에 외부에서 구현 객체를 생성하고 클라이언트에 전달해서 클라이언트와 서버의 실제 의존 관계가 연결되는 것으로 이를 의존관계 주입(DI)이라 한다.

객체 생성 시점에 해당 객체의 참조값을 전달하므로 클라이언트 코드의 변경 없이 클라이언트가 호출하는 대상의 타입을 변경할 수 있다.

 

DI : 정적인 클래스 의존 관계 변경 없이, 동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

 

 

 

Reference:

https://mangkyu.tistory.com/150

 

[Spring] 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유

1. 의존성 주입(Dependency Injection)의 개념과 필요성 [ 의존성 주입(Dependency Injection) 이란? ] Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 의존성 주입(Dependency Inj

mangkyu.tistory.com

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com

 

'Spring' 카테고리의 다른 글

스프링 데이터 접근 기술  (0) 2023.04.28
스프링 빈 등록 방법  (0) 2023.04.27
Spring Test 관련 정리  (0) 2023.04.27
@RequestBody와 @ResponseBody  (0) 2023.04.27
Spring MVC 패턴  (0) 2023.04.27