IOC/DI

사나이장대산·2024년 11월 13일

Spring

목록 보기
18/26

IOC(제어의 역전, Inversion Of Control)

객체의 생성과 관리 권한을 개발자가 아닌 Spring 컨테이너가 담당하는 것을 말한다. 기본적으로 개발자가 객체를 직접 생성하고 관리했지만, Spring에서는 컨테이너가 객체 생성, 주입, 소멸을 관리한다.

  • IOC의 역할

    요리사(개발자)는 필요한 재료를 직접 준비하지 않고, Chef가 알아서 필요한 재료(Bean)을 관리하고 요리사에게 가져다준다.
  • IoC 개념
    1. 객체의 생성 및 생명주기 관리를 개발자가 직접 하는 것이 아니라 컨테이너가 담당한다.
    2. 객체 간의 결합도를 낮춰 유연한 코드가 된다.

DI(의존성 주입, Dependency Injection)

Spring이 객체 간의 의존성을 자동으로 주입해주는 것을 의미한다. 한 객체가 다른 객체를 사용할 때, 해당 객체를 직접 생성하지 않고 Spring이 주입해주는 방식이다. IOC를 구현하는 방식 중 하나이다.

  • DI의 역할

  • 셰프가 요리를 만들 때 필요한 재료(Bean)를 자동으로 요리사에게 가져다주는 과정

  • 요리사(개발자)는 재료를 찾을 필요 없이, Chef가 알아서 제공해준다.

  • 개발자가 직접 관리

// Service 인터페이스
public interface MyService {
    void doSomething();
}

// Repository 인터페이스
public interface MyRepository {
    void queryDatabase();
}

// Service 구현체
public class MyServiceImpl implements MyService {
    private MyRepository myRepository;

    // 의존성 주입
    public MyServiceImpl(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    @Override
    public void doSomething() {
        System.out.println("서비스 작업 실행");
        myRepository.queryDatabase();
    }
}

// Repository 구현체
public class MyRepositoryImpl implements MyRepository {
    @Override
    public void queryDatabase() {
        System.out.println("데이터베이스 쿼리 실행");
    }
}

public class MyApp {
    public static void main(String[] args) {
        MyRepository repo = new MyRepositoryImpl();

				// MyRepository repo2 = new MyRepositoryImplV2();

        MyService myService = new MyServiceImpl(repo);
        
				// MyService myService2 = new MyServiceImpl(repo2);

        myService.doSomething();
    }
}

// 새로운 Repository 구현체
public class MyRepositoryImplV2 implements MyRepository {
    @Override
    public void queryDatabase() {
        System.out.println("데이터베이스 쿼리 실행 V2");
    }
}
  • 객체 간의 강한 결합을 유발한다.
  • 새로운 Service나 Repository가 생긴다면 클라이언트측 코드에 영향이 생긴다.
    Spring Container가 관리(IOC, DI)
// Service 구현체
@Service
public class MyIocService implements MyService {
    
    private final MyRepository myRepository;

    // 생성자 주입(DI 적용)
    @Autowired
    public MyIocService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    @Override
    public void doSomething() {
        System.out.println("IOC 서비스 작업 실행");
        myRepository.queryDatabase();
    }
}

// Repository 구현체
@Repository
public class MyIocRepository implements MyRepository {

    @Override
    public void queryDatabase() {
        // 데이터베이스와 상호작용
        System.out.println("IOC 데이터베이스 쿼리 실행");
    }
}

// Spring Container 관리(IoC 적용)
@ComponentScan(basePackages = "com.example")
public class MyIocApp {

    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyIocApp.class);

        // Service 빈을 가져와서 실행
        MyService service = context.getBean(MyService.class);
        service.doSomething();
    }
}

// 새로운 Repository 구현체
@Repository
public class MyIocRepositoryV2 implements MyRepository {

    @Override
    public void queryDatabase() {
        // 데이터베이스와 상호작용
        System.out.println("IOC 데이터베이스 쿼리 실행 V2");
    }
}
  • 구현 코드가 변경되어도 클라이언트의 코드에는 영향이 없다.

  • 다른 구현체를 구현하여 Bean으로 등록하면 자유롭게 변경이 가능하다.

    • 위 예시 코드는 @Repository 로 등록된 빈이 중복되어 충돌이 발생한다.
  • 의존성 주입(DI), 제어의 역전(IOC)을 통해 객체 간의 결합도를 낮추고 유연한 설계가 가능해진다.

  • IOC/DI

    1. IoC는 객체의 제어권을 개발자가 아닌 Spring 컨테이너에게 넘기는 개념으로, Spring이 객체 생성과 관리를 담당한다.
    2. DI는 Spring이 객체 간의 의존성을 자동으로 주입해주는 기법이다.
    3. 의존관계 주입은 객체 간의 결합도를 낮추고 코드의 유연성과 테스트 가능성을 높여준다.
profile
사나이 張大山 포기란 없다.

0개의 댓글