본문 바로가기
코딩/Spring

[Spring] IOC, DI

by Leedius 2023. 3. 14.

IOC(Inversion of Control)란

"제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.

IoC는 제어의 역전이라고 말하며, 간단히 말해 "제어의 흐름을 바꾼다"라고 한다.

객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.

기존에는 다음과 순서로 객체가 만들어지고 실행되었다.

  1. 객체 생성
  2. 의존성 객체 생성
    클래스 내부에서 생성
  3. 의존성 객체 메소드 호출

하지만, 스프링에서는 다음과 같은 순서로 객체가 만들어지고 실행된다.

  1. 객체 생성
  2. 의존성 객체 주입
    스스로가 만드는것이 아니라 제어권을 스프링에게 위임하여 스프링이 만들어놓은 객체를 주입한다.
  3. 의존성 객체 메소드 호출

스프링이 모든 의존성 객체를 스프링이 실행될때 다 만들어주고 필요한곳에 주입시켜줌으로써 Bean들은 싱글턴 패턴의 특징을 가지며,

제어의 흐름을 사용자가 컨트롤 하는 것이 아니라 스프링에게 맡겨 작업을 처리하게 된다.

 

예제)

우선 아래와 같은 Restaurant , Chef클래스가 있다고 하자.

위 클래스에서는 serving이라는 메소드에 chef의 cooking이라는 메소드를 쓰기위해 Restaurant클래스에

chef에 대한 객체를 생성 해줬다.

여기서 만약에 기존Chef를 자르고 SuperChef라는 클래스를 만들어 다음과 같이 SuperCooking이라는 메소드를 만들면

Restaurant 클래스에서는 객체 생성도 다시해줘야하고 메소드도 바꿔야한다. 결합도가 매우 높다고 할 수 있다.

여기서 결합도를 한단계 낮추려면 인터페이스를 사용한다.

다음과 같이 인터페이스를 사용하여 메소드명을 통일 해주는 것이다

이렇게 요리를 하는 메소드를 cooking으로 통일해서 위에 chef와 superChef의 요리 메소드가 달라

메소드를 수정하는 일이 없어지기 때문에 결합도가 한단계 낮아진다.

 

그리고 다음 그림처럼 각클래스에 인터페이스클래스를 상속을 해주면

 

다음 그림처럼 자료형을 인터페이스로 통일 할 수 있어 결합도가 또 한단계 낮아진다.

 

이제 여기서 스프링을 사용하는 중이면 다음과 같이 선언만 해줘도 객체를 생성해 주기 때문에 결합도가 낮아진다.

 

 

 

DI(Dependency Injection)의존성 주입 이란

DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로,
객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다.

DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.

 

1.프로그램 실행 시 필요할 것 같은 객체는 모두 만들어준다.(class전에)
   프로젝스 생성 시 기본 패키지 안에 있는 모든 클래스는
   스프링이 자동으로 객체를 생성하는 후보가 된다(자격이 된다).

2.객체 생성 어노테이션을 사용하여 객체를 생성한다.
   아래 네 가지 중 하나라도 붙어있는 클래스는 스프링이 객체를 자동 생성
   a. @Controller  ->  스프링 초창기 버전에 사용했던 어노테이션.
----------------------------------------------------------------------------------
   b. @Component
   c. @Service("만들어질 객체명 지정")
      예시)

  @Service
        class MyServiceImpl{....}
        -> MyServiceImpl myServiceImpl = new MyServiceImpl();
        
        @Service("만들어질 객체의 이름")
        class MyServiceImpl{....}
        -> MyServiceImpl 만들어질 객체의 이름 = new MyServiceImpl();


   d. @Repository
   TestController testController = new TestController();  (객체 이름은 클래스명에서 앞글자만 소문자로 바꿔서 사용)

 

2.만들어진 객체 중 필요한 객체를 의존성 주입시킨다.
   -의존성 주입을 통해 객체를 생성하는 것도 어노테이션을 사용!  
   a. @Autowired() - 자료형을 구분하여 객체의 의존성 주입을 시킨다.
     1번 예시)
     @Component
     class Board{...} -> Board board = new Board();

     @Component
     class Member{...} -> Member member = new Member();

     @Autowired
     private Member m; ->자료형이 Member랑 일치 하므로 Member자료형으로 m이라는 객체가 생성된다.

     2번예시)
     @Component
     class Avante implements Car{...} -> Avante avante = new Avante();

     @Component
     class Sonate implements Car{...} -> Sonate sonate = new Sonate();

     @Autowired
     private Car c; -> 오류 발생!!!

     @Resource(name = "avante")
     private Car c;

   b. @Resource() - 만들어진 객체명을 기준으로 의존성 주입을 시킨다.

@Service("만들어질 객체의 이름")
  class MyServiceImpl{....}
  -> MyServiceImpl 만들어질 객체의 이름 = new MyServiceImpl();
     Private MyServiceImpl service;

댓글