5주차 Unit 7.1 — IoC (제어의 역전) 개념

Psj·2026년 5월 27일

F-lab

목록 보기
175/240

Unit 7.1 — IoC (제어의 역전) 개념

F-LAB JAVA · 5주차 · Phase 7 · 제어의 역전 (IoC)
🌱 Phase 7 시작 — ★ 깊이 파기 (Spring 의 정신)


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • IoC (제어의 역전) 의 개념은?
  • 전통 방식 vs IoC 방식 의 차이는?
  • "역전 (Inversion)" 에서 무엇이 뒤집히는가 ?
  • 객체 생성·연결 권한이 외부로 넘어간다 는 의미는?
  • 누가 그 결정을 하는가 (다른 객체/프레임워크/컨테이너) ?
  • main() 외에 IoC 가 어디서 일어나는가 ?
  • IoC 의 효과 는?
  • IoC 와 전략 패턴 의 연결은?
  • IoC 가 Spring 의 정신인 이유는?

🎯 핵심 한 문장

IoC (Inversion of Control, 제어의 역전) 는 객체가 자신이 사용할 객체를 스스로 생성·선택하던 제어 권한을, 외부 (다른 객체·프레임워크·컨테이너) 로 넘기는 것이다.
전통 방식에서는 UserDao 가 생성자에서 new NConnectionMaker() 처럼 자신이 사용할 객체를 스스로 결정·생성 했다.
IoC 방식에서는 "어떤 ConnectionMaker 를 쓸지" 의 결정 권한이 UserDao 가 아닌 외부로 넘어가 UserDao 는 주입받은 것을 사용만 한다.
"역전 (Inversion)" 에서 뒤집히는 것은 제어의 흐름 (control flow) — 객체가 자신의 의존 객체를 직접 제어 (생성·선택) 하던 것이, 외부가 제어하고 객체는 수동적으로 받는 것으로 뒤집힌다.
이 결정을 하는 주체는 다른 객체 (조립 코드), 프레임워크, 또는 IoC 컨테이너 (ApplicationContext) 이며, IoC 는 main() 의 조립뿐 아니라 템플릿 메소드 (부모가 자식 호출), 프레임워크 (프레임워크가 내 코드 호출) 등 여러 곳에서 일어나는, Spring 의 근본 정신이다.

비유 — 식당 vs 출장 요리

IoC = 제어의 역전 (주방 통제권):

전통 방식 (내가 장 봄):
  - 요리사가 직접 마트 가서 재료 삼
  - 어떤 재료 살지 요리사가 결정
  - 재료 생성·선택을 요리사가 제어

IoC 방식 (재료 배달):
  - 재료가 배달됨 (주입)
  - 어떤 재료? 외부가 결정
  - 요리사는 받아서 요리만
  - 재료 선택 권한이 외부로 (역전)

역전되는 것:
  - 제어 흐름 (control flow)
  - 요리사가 재료 통제 → 외부가 통제

누가 결정:
  - 식자재 회사 (외부 객체)
  - 또는 발주 시스템 (컨테이너)

할리우드 원칙:
  - "전화하지 마, 우리가 할게"
  - 요리사가 마트에 전화 X
  - 회사가 알아서 배달

→ IoC = 객체 생성·선택 권한이 외부로, 제어 흐름의 역전, Spring 의 정신.


🧭 9개 섹션 로드맵

1. IoC의 개념
2. 전통 방식 vs IoC 방식
3. 무엇이 역전되는가
4. 생성·연결 권한 이동
5. 누가 결정하는가
6. main 외의 IoC
7. IoC의 효과
8. IoC와 전략 패턴 (Spring 정신)
9. 면접 + 자기 점검

1️⃣ IoC의 개념

1.1 IoC

IoC (Inversion of Control):

  제어의 역전.

  객체가 자신이 사용할 객체를
  스스로 생성·선택하지 않고,
  외부가 결정·주입.

1.2 제어란

제어 (Control) 란:

  객체 생성·연결·관리:
    - "어떤 객체 쓸지" 결정
    - 객체 생성
    - 연결 (의존)
    - 생명주기

  → 이 제어를 누가?

1.3 역전

역전 (Inversion):

  전통: 객체가 제어 (스스로)
  IoC: 외부가 제어 (역전)

  → 제어 주체가 바뀜

1.4 ILIC 의 맥락

// 전통 (제어를 객체가)
public class ShipmentDaoTraditional {
    private ConnectionMaker connectionMaker;
    public ShipmentDaoTraditional() {
        this.connectionMaker = new NConnectionMaker();   // 스스로 결정
    }
}

// IoC (제어를 외부가)
public class ShipmentDaoIoC {
    private final ConnectionMaker connectionMaker;
    public ShipmentDaoIoC(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 외부가 결정, 주입받음
    }
}
class NConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

1.5 자기 점검 답변

IoC (제어의 역전) 의 개념은?

:
1. IoC:

  • 제어의 역전
  • 외부가 결정·주입
  1. 제어:

    • 생성·연결·관리
  2. 역전:

    • 객체 → 외부
  3. 결과:

    • 객체는 받아서 사용

2️⃣ 전통 방식 vs IoC 방식

2.1 전통 방식

// 전통 방식 — 자기가 결정·생성
public class ShipmentDao {
    private ConnectionMaker connectionMaker;
    
    public ShipmentDao() {
        // 자기가 사용할 객체를 스스로 생성
        this.connectionMaker = new NConnectionMaker();
    }
}
// ShipmentDao 가 NConnectionMaker 를 직접 결정

2.2 IoC 방식

// IoC 방식 — 외부에서 주입
public class ShipmentDao {
    private final ConnectionMaker connectionMaker;
    
    public ShipmentDao(ConnectionMaker connectionMaker) {
        // 외부에서 주입받음 (스스로 생성 X)
        this.connectionMaker = connectionMaker;
    }
}
// 어떤 ConnectionMaker? 외부가 결정

2.3 차이

항목전통IoC
객체 생성자기가 (new)외부가
결정 권한자기외부
결합도
유연성낮음높음

2.4 결정적 차이

결정적 차이:

전통:
  - new 로 직접 생성
  - 구체 클래스 결정
  - 강결합

IoC:
  - 주입받음
  - 외부 결정
  - 느슨

2.5 ILIC 의 맥락

// 전통 vs IoC 비교

// 전통 — ShipmentDao 가 제어
class ShipmentDaoOld {
    private ConnectionMaker cm = new CustomerAConnectionMaker();   // 직접
    // 고객사 바뀌면 → 코드 수정
}

// IoC — 외부가 제어
class ShipmentDaoNew {
    private final ConnectionMaker cm;
    ShipmentDaoNew(ConnectionMaker cm) { this.cm = cm; }   // 주입
    // 고객사 바뀌면 → 주입만 다르게 (코드 X)
}

// 외부 조립
ConnectionMaker maker = new CustomerAConnectionMaker();
ShipmentDaoNew dao = new ShipmentDaoNew(maker);   // 외부가 결정·주입
class CustomerAConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

2.6 자기 점검 답변

전통 방식 vs IoC 방식의 차이는?

:
1. 전통:

  • new 직접 생성
  • 자기 결정
  1. IoC:

    • 주입받음
    • 외부 결정
  2. 차이:

    • 결정 권한 위치
  3. 결합도:

    • 강 vs 약

3️⃣ 무엇이 역전되는가

3.1 제어 흐름

역전되는 것 — 제어 흐름:

전통:
  객체 → 의존 객체 제어
  (생성·선택)

IoC:
  외부 → 의존 객체 제어
  객체는 받음 (수동)

→ 제어 흐름 방향 역전

3.2 능동 → 수동

능동 → 수동:

전통 (능동):
  - 객체가 적극적
  - "내가 만들고 선택"

IoC (수동):
  - 객체가 수동적
  - "받아서 사용"

3.3 의존성 결정

의존성 결정 역전:

전통:
  - 객체가 의존성 결정

IoC:
  - 외부가 의존성 결정
  - 객체에 주입

→ 결정 권한 역전

3.4 시각화

제어 흐름 역전:

전통:
  [ShipmentDao] → new → [NConnectionMaker]
   (ShipmentDao 가 생성 제어)

IoC:
  [외부] → 생성 → [NConnectionMaker]
              ↓ 주입
        [ShipmentDao]
   (외부가 생성 제어, DAO 는 받음)

3.5 ILIC 의 맥락

// 무엇이 역전?

// 전통 — 제어가 ShipmentDao 에
class ShipmentDaoOld {
    private ConnectionMaker cm;
    ShipmentDaoOld() {
        cm = new CustomerAConnectionMaker();   // ShipmentDao 가 제어
        // "내가 어떤 연결 쓸지 결정"
    }
}

// IoC — 제어가 외부로 (역전)
class ShipmentDaoNew {
    private final ConnectionMaker cm;
    ShipmentDaoNew(ConnectionMaker cm) {
        this.cm = cm;   // 외부가 제어, 받음
        // "주는 거 쓸게"
    }
}

// 역전되는 것: "어떤 연결 쓸지" 의 제어
// ShipmentDao → 외부
class CustomerAConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

3.6 자기 점검 답변

"역전 (Inversion)" 에서 무엇이 뒤집히는가?

:
1. 제어 흐름:

  • 객체 → 외부
  1. 능동 → 수동:

    • 만듦 → 받음
  2. 의존성 결정:

    • 객체 → 외부
  3. 방향:

    • 제어 주체 역전

4️⃣ 생성·연결 권한 이동

4.1 권한 이동

생성·연결 권한 이동:

  객체:
    - 생성 권한 X
    - 연결 권한 X

  외부:
    - 생성 권한
    - 연결 권한

4.2 생성 권한

생성 권한:

전통:
  - new ConcreteClass()
  - 객체가 생성

IoC:
  - 외부가 생성
  - 객체는 받음

4.3 연결 권한

연결 권한:

  의존 객체 연결:
    - "A 가 B 를 사용"
    - 누가 연결?

전통: A 가 B 생성·연결
IoC: 외부가 연결 (주입)

4.4 객체는 사용만

객체는 사용만:

  IoC 에서 객체:
    - 받은 것 사용
    - 생성 X
    - 선택 X
    - 비즈니스 집중

→ 관심사 분리

4.5 ILIC 의 맥락

// 권한 이동

// 외부 (조립 코드) — 생성·연결 권한
public class ObjectAssembler {
    public ShipmentDao assemble() {
        // 생성 권한 (외부)
        ConnectionMaker cm = new CustomerAConnectionMaker();
        ShipmentDao dao = new ShipmentDao(cm);   // 연결 권한 (외부)
        return dao;
    }
}

// ShipmentDao — 사용만
public class ShipmentDao {
    private final ConnectionMaker connectionMaker;
    public ShipmentDao(ConnectionMaker cm) {
        this.connectionMaker = cm;   // 받음
    }
    public void add(Shipment s) throws Exception {
        Connection c = connectionMaker.makeConnection();   // 사용만
        // 생성·선택 X, 비즈니스 집중
    }
}
// 생성·연결 = 외부 (Assembler)
// 사용 = ShipmentDao
class CustomerAConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

4.6 자기 점검 답변

객체 생성·연결 권한이 외부로 넘어간다는 의미는?

:
1. 권한 이동:

  • 객체 → 외부
  1. 생성 권한:

    • 외부가 new
  2. 연결 권한:

    • 외부가 주입
  3. 객체:

    • 사용만

5️⃣ 누가 결정하는가

5.1 결정 주체

누가 결정:

  객체 생성·연결 결정:
    1. 다른 객체 (조립 코드)
    2. 프레임워크
    3. IoC 컨테이너 (ApplicationContext)

5.2 다른 객체

// 1. 다른 객체 (팩토리/조립)
public class DaoFactory {
    public ShipmentDao shipmentDao() {
        return new ShipmentDao(connectionMaker());   // 결정·조립
    }
    public ConnectionMaker connectionMaker() {
        return new NConnectionMaker();   // 결정
    }
}
// DaoFactory 가 결정

5.3 프레임워크

2. 프레임워크:

  프레임워크가 객체 관리:
    - 생성
    - 연결
    - 호출

  → 내 코드를 프레임워크가

5.4 IoC 컨테이너

// 3. IoC 컨테이너 (Spring)
@Configuration
public class DaoConfig {
    @Bean
    public ShipmentDao shipmentDao() {
        return new ShipmentDao(connectionMaker());
    }
    @Bean
    public ConnectionMaker connectionMaker() {
        return new NConnectionMaker();
    }
}
// ApplicationContext 가 결정·관리
// → Phase 8

5.5 발전 단계

발전 단계:

1. main 직접 (초기)
2. 팩토리 객체 (DaoFactory)
3. IoC 컨테이너 (Spring)

→ 점점 외부화·자동화

5.6 ILIC 의 맥락

// 결정 주체 발전

// 1. main 에서 직접
public static void main(String[] args) throws Exception {
    ConnectionMaker cm = new CustomerAConnectionMaker();
    ShipmentDao dao = new ShipmentDao(cm);   // main 이 결정
}

// 2. 팩토리 객체
public class DaoFactory {
    public ShipmentDao shipmentDao() {
        return new ShipmentDao(connectionMaker());   // 팩토리가 결정
    }
    public ConnectionMaker connectionMaker() {
        return new CustomerAConnectionMaker();
    }
}

// 3. IoC 컨테이너 (Spring) — Phase 8
@Configuration
public class DaoConfig {
    @Bean public ShipmentDao shipmentDao() {
        return new ShipmentDao(connectionMaker());   // 컨테이너가 결정
    }
    @Bean public ConnectionMaker connectionMaker() {
        return new CustomerAConnectionMaker();
    }
}
class CustomerAConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

5.7 자기 점검 답변

누가 그 결정을 하는가?

:
1. 주체:

  • 다른 객체
  • 프레임워크
  • IoC 컨테이너
  1. 다른 객체:

    • 팩토리/조립
  2. 컨테이너:

    • ApplicationContext
  3. 발전:

    • main → 팩토리 → 컨테이너

6️⃣ main 외의 IoC

6.1 IoC 가 일어나는 곳

IoC 가 일어나는 곳:

  - main 조립 (명시적)
  - 템플릿 메소드 (부모가 자식 호출)
  - 프레임워크 (프레임워크가 내 코드 호출)
  - 이벤트 리스너 (콜백)
  - IoC 컨테이너

6.2 템플릿 메소드

템플릿 메소드의 IoC:

  부모가 자식 메서드 호출:
    - 제어가 부모
    - 자식은 호출당함

  → 작은 IoC (Phase 5.1)

6.3 프레임워크의 IoC

프레임워크의 IoC:

  라이브러리: 내가 호출
  프레임워크: 프레임워크가 호출

  - 내 코드를 프레임워크가
  - 제어가 프레임워크

  → 할리우드 원칙

6.4 콜백/이벤트

콜백/이벤트의 IoC:

  콜백 등록:
    - 내가 등록
    - 시스템이 호출 (제어 역전)

  이벤트 리스너:
    - 이벤트 시 호출당함

6.5 ILIC 의 맥락

// 다양한 IoC

// 1. 템플릿 메소드 (부모가 자식 호출)
abstract class ShipmentDaoTemplate {
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();   // 부모가 자식 호출 (IoC)
    }
    protected abstract Connection getConnection() throws Exception;
}

// 2. 프레임워크 (Spring 이 호출)
@RestController
class ShipmentController {
    @GetMapping("/shipments/{id}")   // Spring 이 이 메서드 호출 (IoC)
    public Shipment get(@PathVariable Long id) {
        return null;
    }
}

// 3. 이벤트 리스너 (호출당함)
@EventListener
public void onShipmentCreated(ShipmentCreatedEvent event) {
    // Spring 이 이벤트 시 호출 (IoC)
}

// 모두 제어가 역전 (내가 호출 X, 호출당함)
record ShipmentCreatedEvent(Long id) {}

6.6 자기 점검 답변

main() 외에 IoC가 어디서 일어나는가?

:
1. 여러 곳:

  • 템플릿 메소드
  • 프레임워크
  • 콜백/이벤트
  1. 템플릿 메소드:

    • 부모가 자식 호출
  2. 프레임워크:

    • 프레임워크가 내 코드
  3. 콜백:

    • 호출당함

7️⃣ IoC의 효과

7.1 효과 정리

IoC 효과:

1. 결합도 ↓
2. 유연성 ↑
3. 테스트 용이
4. 관심사 분리
5. 재사용

7.2 결합도

결합도 ↓:

  객체가 구체 모름:
    - 인터페이스 의존
    - 외부 주입

  → 느슨한 결합

7.3 테스트

// 테스트 용이 (Mock 주입)
@Test
void test() {
    ConnectionMaker mock = mock(ConnectionMaker.class);
    ShipmentDao dao = new ShipmentDao(mock);   // Mock 주입
    // 실제 DB 없이 테스트
}
// IoC → Mock 주입 → 단위 테스트

7.4 유연성

유연성:

  구현 교체:
    - 주입만 다르게
    - 코드 변경 X

  → 런타임 유연

7.5 ILIC 의 맥락

// IoC 효과

// 1. 테스트 (Mock 주입)
@Test
void testShipmentDao() {
    ConnectionMaker mockMaker = mock(ConnectionMaker.class);
    ShipmentDao dao = new ShipmentDao(mockMaker);
    // 실제 DB 없이 테스트
}

// 2. 환경별 구현
@Profile("prod")
@Bean ConnectionMaker prodMaker() { return new ProdConnectionMaker(); }

@Profile("test")
@Bean ConnectionMaker testMaker() { return new H2ConnectionMaker(); }
// 환경별 주입 (코드 변경 X)

// 3. 결합도 ↓ → 유지보수 ↑
class ProdConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}
class H2ConnectionMaker implements ConnectionMaker {
    public Connection makeConnection() { return null; }
}

7.6 자기 점검 답변

IoC의 효과는?

:
1. 효과:

  • 결합도 ↓
  • 유연성 ↑
  1. 테스트:

    • Mock 주입
  2. 유연성:

    • 구현 교체
  3. 관심사:

    • 분리

8️⃣ IoC와 전략 패턴 (Spring 정신)

8.1 전략 패턴 → IoC

전략 패턴 → IoC:

  전략 패턴:
    - 전략 주입 (Phase 6)

  IoC:
    - 주입을 일반화
    - 제어 역전 개념

→ 전략 주입이 IoC 의 한 예

8.2 주입의 일반화

주입의 일반화:

  전략 패턴:
    - 특정 전략 주입

  IoC:
    - 모든 의존성 주입
    - 일반 원칙

→ DI (Phase 8)

8.3 Spring 의 정신

Spring 의 정신:

  Spring = IoC 컨테이너:
    - 객체 생성·연결·관리
    - 제어를 컨테이너가

  → IoC 가 Spring 핵심

8.4 DI 로 발전

DI 로 발전:

  IoC (개념):
    - 제어 역전

  DI (구현):
    - 의존성 주입
    - IoC 의 구체 방법

→ Phase 8 DI

8.5 ILIC 의 맥락

// 전략 패턴 → IoC → DI

// 전략 패턴 (Phase 6)
class ShipmentDao {
    private final ConnectionMaker connectionMaker;   // 전략
    ShipmentDao(ConnectionMaker cm) { this.connectionMaker = cm; }
}

// IoC 개념 (Phase 7)
// → 제어(생성·선택)를 외부로

// DI 구현 (Phase 8) — Spring
@Service
class ShipmentService {
    private final ShipmentDao shipmentDao;
    
    // Spring 이 ShipmentDao 주입 (IoC 컨테이너)
    public ShipmentService(ShipmentDao shipmentDao) {
        this.shipmentDao = shipmentDao;   // DI
    }
}
// 전략 주입 → IoC 개념 → DI 구현 (Spring)
interface ConnectionMaker { Connection makeConnection() throws Exception; }

8.6 자기 점검 답변

IoC와 전략 패턴의 연결은?

:
1. 연결:

  • 전략 주입 = IoC 예
  1. 일반화:

    • 모든 의존성 주입
  2. Spring 정신:

    • IoC 컨테이너
  3. DI:

    • IoC 의 구현

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
IoC?제어의 역전 (외부가 결정)
전통 vs IoC?new 직접 vs 주입
무엇이 역전?제어 흐름 (생성·선택)
권한 이동?객체 → 외부
누가 결정?객체/프레임워크/컨테이너
main 외 IoC?템플릿/프레임워크/콜백
효과?결합도 ↓, 테스트
전략 패턴 연결?주입의 일반화
Spring 정신?IoC 컨테이너
DI?IoC 의 구현

9.2 자기 점검 체크리스트

IoC

  • 제어 역전

전통 vs IoC

  • new vs 주입

무엇이 역전

  • 제어 흐름

권한 이동

  • 객체 → 외부

누가 결정

  • 컨테이너

main 외

  • 템플릿/프레임워크

효과

  • 결합도, 테스트

Spring 정신

  • IoC

9.3 추가 심화 질문

Q1: IoC 와 DI 차이?

답:

  • IoC: 제어 역전 (넓은 개념)
  • DI: 의존성 주입 (IoC 구현 방법)
  • DI 는 IoC 의 한 형태
  • IoC ⊃ DI

Q2: IoC 와 DL (Dependency Lookup)?

답:

  • DI: 주입 (수동적)
  • DL: 조회 (능동적, getBean)
  • 둘 다 IoC
  • DI 가 더 깔끔

Q3: 할리우드 원칙?

답:

  • "Don't call us, we'll call you"
  • 프레임워크가 내 코드 호출
  • IoC 의 표현
  • 제어 역전

Q4: IoC 의 단점?

답:

  • 흐름 추적 어려움
  • 디버깅 복잡
  • 학습 곡선
  • 마법 같음 (이해 필요)

Q5: 프레임워크 vs 라이브러리 IoC?

답:

  • 라이브러리: 내가 호출 (제어 나)
  • 프레임워크: 호출당함 (제어 역전)
  • 프레임워크 = IoC
  • → Unit 7.2

🎯 핵심 요약 — 3줄 정리

1. IoC (제어의 역전)

  • 객체 생성·선택 권한이 객체 자신 → 외부로
  • 전통 (new 직접) vs IoC (주입받음)

2. 무엇이 역전

  • 제어 흐름 (control flow)
  • 능동 (만듦) → 수동 (받음), 결정 권한 외부로

3. 누가 결정 + Spring 정신

  • 다른 객체 / 프레임워크 / IoC 컨테이너
  • 전략 주입의 일반화 → DI → Spring 의 근본 정신

📚 다음으로...

Unit 7.2 — 프레임워크 vs 라이브러리

이번 Unit에서 IoC 개념을 봤다면, 다음은 프레임워크 vs 라이브러리.

  • 누가 흐름을 제어하는가
  • 호출 방향
  • Hollywood Principle
  • Spring 이 프레임워크인 이유

Phase 7 진행 상황

🌱 Phase 7 — 제어의 역전 (IoC)
  ✅ Unit 7.1 IoC 개념 ★깊이 ← 여기
  ⏭ Unit 7.2 프레임워크 vs 라이브러리
  ⏭ Unit 7.3 IoC 컨테이너의 역할

5주차 누적 진행

✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
  ✅ Phase 3~6 (12 Unit)
  🌱 Phase 7 — IoC (1/3 진행)

총: 20/26 Unit

★ 깊이 파기 — IoC 개념 완료

profile
Software Developer

0개의 댓글