5주차 Unit 8.3 — 싱글톤 레지스트리

Psj·2026년 5월 27일

F-lab

목록 보기
180/240

Unit 8.3 — 싱글톤 레지스트리

F-LAB JAVA · 5주차 · Phase 8 · Spring 컨테이너
★ 깊이 파기 — 4주차 동시성과 만나는 지점


📌 학습 목표

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

  • getBean 100번 = 1객체 인 이유는?
  • ApplicationContext = 싱글톤 레지스트리 인가?
  • 모든 빈이 기본 싱글톤 인가?
  • 왜 싱글톤인가 (메모리/GC) ?
  • stateless 가 필요한 이유는? (멀티스레드)
  • 4주차 동시성과의 연결 은?
  • 전통 싱글톤 (getInstance) vs Spring 싱글톤 차이는?
  • 빈에 ConcurrentHashMap 필드는 왜 OK 인가?
  • 싱글톤의 주의점 은?

🎯 핵심 한 문장

ApplicationContext 는 싱글톤 레지스트리로 모든 빈을 기본 싱글톤 (1개 인스턴스) 으로 관리하므로 getBean 을 100번 호출해도 같은 객체가 반환되며, 따라서 빈은 여러 스레드가 공유하므로 상태 (state) 를 갖지 않는 stateless 로 설계해야 한다.
Spring 빈은 기본적으로 싱글톤 이라, 컨테이너에 1개 인스턴스만 존재하고 getBean 을 몇 번 호출하든 같은 객체를 반환한다 (ApplicationContext = 싱글톤 레지스트리).
왜 싱글톤인가 — 서버 환경에서는 초당 수많은 요청이 같은 서비스·DAO 를 사용하는데, 매 요청마다 객체를 생성하면 메모리·GC 부담이 크므로, 1개를 공유하는 것이 효율적이다.
그런데 1개 빈을 여러 스레드가 동시에 사용하므로, 빈이 변경 가능한 인스턴스 상태 (필드) 를 가지면 동시성 문제 (4주차의 가시성·원자성) 가 발생한다 — 따라서 빈은 stateless 로 설계해야 한다.
전통 싱글톤 (getInstance() + private 생성자) 은 구현이 번거롭고 테스트·상속이 어렵지만, Spring 싱글톤은 컨테이너가 관리하여 평범한 객체를 싱글톤으로 쓰며, 빈 필드로 ConcurrentHashMap 같은 스레드 안전한 객체나 final 불변 객체를 두는 것은 안전하다.

비유 — 회사 공용 복합기

싱글톤 레지스트리 = 공용 복합기:

빈 = 공용 복합기 (1대):
  - 회사에 1대 (싱글톤)
  - 모든 직원(스레드) 공유
  - getBean 100번 = 같은 복합기

왜 1대 (싱글톤):
  - 직원마다 복합기 X (낭비)
  - 1대 공유 (효율, 메모리/GC)

stateless 필요:
  - 복합기에 "내 문서" 저장하면 (상태)
  - 다른 직원이 보거나 섞임 (동시성 문제)
  - → 출력하고 바로 가져감 (stateless)

상태 두면 (4주차 동시성):
  - 가시성: 내 설정 다른 사람 안 보임
  - 원자성: 동시 출력 섞임

안전한 필드:
  - 복합기 자체 기능 (불변)
  - 스레드 안전 부품 (ConcurrentHashMap)
  → OK

→ ApplicationContext = 싱글톤 레지스트리 (빈 1개 공유), stateless 필수 (동시성).


🧭 9개 섹션 로드맵

1. getBean 100번 = 1객체
2. ApplicationContext = 싱글톤 레지스트리
3. 모든 빈 기본 싱글톤
4. 왜 싱글톤 (메모리/GC)
5. stateless 필요 (멀티스레드)
6. 4주차 동시성 연결
7. 전통 vs Spring 싱글톤
8. ConcurrentHashMap 필드는 OK
9. 면접 + 자기 점검

1️⃣ getBean 100번 = 1객체

1.1 같은 객체

// getBean 100번 = 1객체
for (int i = 0; i < 100; i++) {
    ShipmentDao dao = ctx.getBean(ShipmentDao.class);
    // 매번 같은 인스턴스
}
// 100번 호출, 1개 객체

1.2 동일성 확인

ShipmentDao dao1 = ctx.getBean(ShipmentDao.class);
ShipmentDao dao2 = ctx.getBean(ShipmentDao.class);

System.out.println(dao1 == dao2);   // true
System.out.println(dao1.equals(dao2));   // true
// 같은 객체 (싱글톤)

1.3 1개만 존재

1개만 존재:

  컨테이너 안:
    - ShipmentDao 빈 1개
    - 모든 요청 공유

  → getBean = 그 1개 반환

1.4 ILIC 의 맥락

public class SingletonProof {
    public void prove(ApplicationContext ctx) {
        // 여러 번 조회
        ShipmentDao dao1 = ctx.getBean(ShipmentDao.class);
        ShipmentDao dao2 = ctx.getBean(ShipmentDao.class);
        ShipmentDao dao3 = ctx.getBean(ShipmentDao.class);
        
        // 모두 같은 인스턴스
        assert dao1 == dao2;   // true
        assert dao2 == dao3;   // true
        
        // 100번, 1000번 호출해도 같은 빈
        // → ILIC 의 431 API 가 같은 ShipmentDao 공유
    }
}
class ShipmentDao { }

1.5 자기 점검 답변

getBean 100번 = 1객체인 이유는?

:
1. 같은 객체:

  • 매번 같은 인스턴스
  1. 동일성:

    • == true
  2. 1개 존재:

    • 컨테이너에 1개
  3. 공유:

    • 모든 요청

2️⃣ ApplicationContext = 싱글톤 레지스트리

2.1 싱글톤 레지스트리

싱글톤 레지스트리:

  ApplicationContext:
    - 싱글톤 객체 등록·관리
    - 빈 = 싱글톤
    - 1개씩 보관

  → 싱글톤 레지스트리

2.2 레지스트리

레지스트리 (Registry):

  등록소:
    - 빈 이름 → 인스턴스
    - 1개씩
    - 조회 제공

  Map<String, Object> (싱글톤)

2.3 싱글톤 관리

싱글톤 관리:

  컨테이너가:
    - 빈 1개 생성
    - 보관
    - 재사용

  → 싱글톤 패턴 대신
  → 컨테이너가 보장

2.4 ILIC 의 맥락

// ApplicationContext = 싱글톤 레지스트리
public class SingletonRegistry {
    public void explain(ApplicationContext ctx) {
        // 컨테이너 내부 (싱글톤 레지스트리):
        // "shipmentDao" → ShipmentDao 인스턴스 (1개)
        // "connectionMaker" → ConnectionMaker 인스턴스 (1개)
        // "shipmentService" → ShipmentService 인스턴스 (1개)
        
        // 각 빈 1개씩, 모든 요청 공유
        // → 싱글톤 레지스트리
        
        ShipmentDao dao = ctx.getBean(ShipmentDao.class);
        // 등록된 1개 반환
    }
}
class ShipmentDao { }

2.5 자기 점검 답변

ApplicationContext = 싱글톤 레지스트리인가?

:
1. 싱글톤 레지스트리:

  • 싱글톤 빈 관리
  1. 레지스트리:

    • 이름 → 인스턴스
  2. 관리:

    • 1개 생성·재사용
  3. 보장:

    • 컨테이너가

3️⃣ 모든 빈 기본 싱글톤

3.1 기본 싱글톤

기본 싱글톤:

  Spring 빈:
    - 기본 스코프 = 싱글톤
    - 명시 안 해도 싱글톤

  @Scope("singleton") 기본

3.2 스코프

빈 스코프:

singleton (기본):
  - 1개 인스턴스

prototype:
  - 매번 새 객체

request/session:
  - 웹 요청/세션별

3.3 싱글톤 스코프

// 기본 싱글톤 (명시 불필요)
@Service
public class ShipmentService {
    // @Scope("singleton") 생략 (기본)
}

// 명시
@Service
@Scope("singleton")
public class ExplicitSingleton { }

3.4 프로토타입

// 프로토타입 (매번 새 객체)
@Component
@Scope("prototype")
public class StatefulBean {
    // getBean 마다 새 인스턴스
}
// 상태 있는 빈 (드묾)

3.5 ILIC 의 맥락

// 대부분 싱글톤 (기본)
@Repository
public class ShipmentDao {   // 싱글톤
    // 모든 요청 공유
}

@Service
public class ShipmentService {   // 싱글톤
    private final ShipmentDao shipmentDao;
    public ShipmentService(ShipmentDao dao) { this.shipmentDao = dao; }
}

@RestController
public class ShipmentController {   // 싱글톤
    private final ShipmentService service;
    public ShipmentController(ShipmentService s) { this.service = s; }
}
// 모두 싱글톤 → stateless 설계 필요 (다음)

3.6 자기 점검 답변

모든 빈이 기본 싱글톤인가?

:
1. 기본 싱글톤:

  • 명시 안 해도
  1. 스코프:

    • singleton 기본
  2. 프로토타입:

    • 매번 새 (드묾)
  3. 대부분:

    • 싱글톤

4️⃣ 왜 싱글톤 (메모리/GC)

4.1 서버 환경

서버 환경:

  초당 수많은 요청:
    - 같은 서비스/DAO 사용
    - 매번 생성하면?
    - 객체 폭증

4.2 매번 생성 문제

매번 생성 문제:

  요청마다 객체:
    - 메모리 ↑
    - GC 부담
    - 생성 비용

  초당 1000 요청 × 객체 N개
  = 폭증

4.3 싱글톤 효율

싱글톤 효율:

  1개 공유:
    - 메모리 절약
    - GC 부담 ↓
    - 생성 비용 1회

  → 서버 환경 적합

4.4 stateless 전제

stateless 전제:

  싱글톤 가능 이유:
    - 빈이 stateless
    - 상태 없음
    - 공유 안전

  → 1개로 충분

4.5 ILIC 의 맥락

// 왜 싱글톤 (ILIC 서버)
@Service
public class ShipmentService {
    private final ShipmentDao shipmentDao;   // 불변 (안전)
    
    public ShipmentService(ShipmentDao dao) {
        this.shipmentDao = dao;
    }
    
    // 메서드 — 상태 없음 (stateless)
    public void processShipment(Shipment shipment) {
        // 파라미터/지역 변수만 (스레드별)
        validate(shipment);
        shipmentDao.add(shipment);
    }
    private void validate(Shipment s) { }
}

// ILIC: 초당 수많은 요청
// - 매번 ShipmentService 생성하면 메모리/GC 폭증
// - 1개 공유 (싱글톤) → 효율
// - stateless 이므로 공유 안전
class ShipmentDao { void add(Shipment s) {} }

4.6 자기 점검 답변

왜 싱글톤인가 (메모리/GC) ?

:
1. 서버 환경:

  • 수많은 요청
  1. 매번 생성:

    • 메모리/GC 폭증
  2. 싱글톤 효율:

    • 1개 공유
  3. 전제:

    • stateless

5️⃣ stateless 필요 (멀티스레드)

5.1 stateless

stateless (무상태):

  빈이 인스턴스 상태(필드)를
  갖지 않음.

  - 변경 가능 필드 X
  - 요청별 데이터는 파라미터/지역

5.2 왜 필요

왜 필요:

  싱글톤 빈:
    - 여러 스레드 공유
    - 인스턴스 필드 = 공유 상태

  상태 있으면:
    - 동시성 문제
    - 데이터 섞임

5.3 위험한 상태

// ❌ 위험 (인스턴스 상태)
@Service
public class ShipmentServiceBad {
    private Shipment currentShipment;   // 인스턴스 상태 (위험!)
    
    public void process(Shipment s) {
        this.currentShipment = s;   // 스레드 A 설정
        // 스레드 B 가 동시에 다른 s 설정 → 섞임
        save(this.currentShipment);   // 어느 s?
    }
    private void save(Shipment s) { }
}

5.4 안전한 stateless

// ✓ 안전 (stateless)
@Service
public class ShipmentServiceGood {
    private final ShipmentDao shipmentDao;   // 불변 (안전)
    
    public ShipmentServiceGood(ShipmentDao dao) {
        this.shipmentDao = dao;
    }
    
    public void process(Shipment s) {
        // 파라미터/지역 변수 (스레드별, 안전)
        validate(s);
        shipmentDao.add(s);
        // 인스턴스 상태 변경 X
    }
    private void validate(Shipment s) { }
}
class ShipmentDao { void add(Shipment s) {} }

5.5 ILIC 의 맥락

// stateless 설계 (ILIC)
@Service
public class FreightService {
    private final FreightRateRepository rateRepo;   // 불변 의존성
    
    public FreightService(FreightRateRepository repo) {
        this.rateRepo = repo;
    }
    
    // stateless 메서드
    public BigDecimal calculate(Shipment shipment) {
        // 모든 데이터를 파라미터/지역 변수로 (스레드별)
        BigDecimal rate = rateRepo.findRate(shipment.getRoute());
        BigDecimal weight = shipment.getWeight();
        return weight.multiply(rate);
        // 인스턴스 필드에 저장 X (stateless)
    }
}

// ❌ 절대 하면 안 됨
// private BigDecimal lastCalculatedFreight;   // 동시성 문제!
class FreightRateRepository {
    BigDecimal findRate(String route) { return BigDecimal.ONE; }
}

5.6 자기 점검 답변

stateless가 필요한 이유는? (멀티스레드)

:
1. stateless:

  • 인스턴스 상태 없음
  1. :

    • 싱글톤 공유
    • 상태 = 공유 상태
  2. 위험:

    • 동시성 문제
  3. 안전:

    • 파라미터/지역

6️⃣ 4주차 동시성 연결

6.1 연결 지점

4주차 동시성 연결:

  싱글톤 빈 + 멀티스레드:
    - 인스턴스 상태 = 공유 변수
    - 가시성/원자성 문제

  → 4주차 동시성이 여기서

6.2 가시성 문제

// 가시성 문제 (싱글톤 빈)
@Service
public class CounterService {
    private boolean active = true;   // 가시성 위험
    
    // 스레드 A: active 변경
    // 스레드 B: 변경 안 보일 수 있음 (캐시)
    // → 4주차 가시성 문제
}

6.3 원자성 문제

// 원자성 문제 (싱글톤 빈)
@Service
public class CounterService {
    private int count = 0;   // 원자성 위험
    
    public void increment() {
        count++;   // 여러 스레드 동시 → 손실
        // → 4주차 원자성 문제
    }
}

6.4 동시성 도구 적용

// 정말 상태 필요하면 — 4주차 도구
@Service
public class SafeCounterService {
    // Atomic (원자성 + 가시성)
    private final AtomicInteger count = new AtomicInteger();
    
    public void increment() {
        count.incrementAndGet();   // 안전 (4주차 CAS)
    }
    
    // 또는 volatile (가시성)
    private volatile boolean active = true;
}
// 4주차 동시성 도구로 안전하게

6.5 ILIC 의 맥락

// 싱글톤 빈 + 4주차 동시성 (ILIC)

@Service
public class ShipmentMetricsService {
    // 통계는 상태 필요 → 4주차 동시성 도구
    private final AtomicLong totalProcessed = new AtomicLong();   // Atomic
    private final LongAdder requestCount = new LongAdder();        // 고경쟁
    private volatile boolean monitoringEnabled = true;            // volatile
    
    // 싱글톤 빈이지만 동시성 안전
    public void recordProcessing() {
        totalProcessed.incrementAndGet();   // 원자성 (4주차 CAS)
        requestCount.increment();            // 고경쟁 (4주차 LongAdder)
    }
    
    public long getTotal() {
        return totalProcessed.get();   // 가시성 (Atomic 내부 volatile)
    }
}
// 싱글톤 빈에 상태 필요 시 → 4주차 동시성 도구 필수
// 5주차(싱글톤) + 4주차(동시성) 만나는 지점

6.6 자기 점검 답변

4주차 동시성과의 연결은?

:
1. 연결:

  • 싱글톤 + 멀티스레드
  • 인스턴스 상태 = 공유
  1. 가시성:

    • 변경 안 보임
  2. 원자성:

    • count++ 손실
  3. 도구:

    • Atomic/volatile (4주차)

7️⃣ 전통 vs Spring 싱글톤

7.1 전통 싱글톤

// 전통 싱글톤 (getInstance)
public class TraditionalSingleton {
    private static final TraditionalSingleton INSTANCE 
        = new TraditionalSingleton();
    
    private TraditionalSingleton() { }   // private 생성자
    
    public static TraditionalSingleton getInstance() {
        return INSTANCE;
    }
}

7.2 전통 싱글톤 단점

전통 싱글톤 단점:

  - private 생성자 (상속 어려움)
  - static (테스트 어려움)
  - 인터페이스 구현 제약
  - DI 어려움
  - 전역 상태 (안티패턴 논란)

7.3 Spring 싱글톤

Spring 싱글톤:

  평범한 객체:
    - 일반 클래스
    - 컨테이너가 1개 관리

  - 인터페이스 OK
  - 테스트 쉬움 (Mock)
  - DI 자연스러움

7.4 차이

항목전통Spring
구현getInstance평범한 객체
생성자privatepublic
범위JVM 전역컨테이너
테스트어려움쉬움
DI어려움자연

7.5 ILIC 의 맥락

// 전통 싱글톤 (번거로움)
public class ConnectionPoolOld {
    private static final ConnectionPoolOld INSTANCE = new ConnectionPoolOld();
    private ConnectionPoolOld() { }
    public static ConnectionPoolOld getInstance() { return INSTANCE; }
    // 테스트 어려움, DI X, 상속 X
}

// Spring 싱글톤 (평범)
@Component
public class ConnectionPool {
    // 평범한 클래스
    // 컨테이너가 싱글톤 관리
    // 인터페이스 구현 OK, 테스트 쉬움, DI 자연
}

// 사용 (DI)
@Service
public class ShipmentService {
    private final ConnectionPool pool;   // 주입 (전통은 getInstance)
    public ShipmentService(ConnectionPool pool) {
        this.pool = pool;
    }
}
// Spring 싱글톤: 평범한 객체 + 컨테이너 관리

7.6 자기 점검 답변

전통 싱글톤 (getInstance) vs Spring 싱글톤 차이는?

:
1. 전통:

  • getInstance, private 생성자
  1. 단점:

    • 테스트/DI 어려움
  2. Spring:

    • 평범한 객체
  3. 차이:

    • 컨테이너 관리, DI 자연

8️⃣ ConcurrentHashMap 필드는 OK

8.1 안전한 필드

안전한 필드:

  싱글톤 빈에 가능:
    - final 불변 객체
    - 스레드 안전 객체 (ConcurrentHashMap)
    - 읽기 전용 데이터

8.2 왜 OK

왜 OK:

  ConcurrentHashMap:
    - 스레드 안전 (내부 동기화)
    - 동시 접근 안전

  → 싱글톤 빈 필드 OK

8.3 안전한 예

// 안전한 필드 (싱글톤 빈)
@Component
public class CacheService {
    // 스레드 안전 (OK)
    private final ConcurrentHashMap<Long, Shipment> cache 
        = new ConcurrentHashMap<>();
    
    public void put(Shipment s) {
        cache.put(s.getId(), s);   // 스레드 안전
    }
    
    public Shipment get(Long id) {
        return cache.get(id);   // 스레드 안전
    }
}
// ConcurrentHashMap = 스레드 안전 → 싱글톤 빈 OK

8.4 불변 객체

// 불변 객체 필드 (OK)
@Component
public class ConfigHolder {
    private final FreightConfig config;   // 불변 (OK)
    
    public ConfigHolder() {
        this.config = loadConfig();
    }
    // 불변이므로 공유 안전
    private FreightConfig loadConfig() { return new FreightConfig(); }
    record FreightConfig() {}
}

8.5 ILIC 의 맥락

// 안전한 싱글톤 빈 필드 (ILIC)
@Component
public class ShipmentCache {
    // 1. 스레드 안전 컬렉션 (OK)
    private final ConcurrentHashMap<Long, Shipment> cache 
        = new ConcurrentHashMap<>();
    
    // 2. 불변 의존성 (OK)
    private final ShipmentDao shipmentDao;
    
    // 3. 동시성 도구 (OK, 4주차)
    private final AtomicLong hitCount = new AtomicLong();
    
    public ShipmentCache(ShipmentDao dao) {
        this.shipmentDao = dao;
    }
    
    public Shipment get(Long id) {
        Shipment cached = cache.get(id);   // 스레드 안전
        if (cached != null) {
            hitCount.incrementAndGet();   // 원자성 (4주차)
            return cached;
        }
        Shipment loaded = shipmentDao.get(id);
        cache.put(id, loaded);   // 스레드 안전
        return loaded;
    }
    
    // ❌ 절대 안 됨:
    // private Shipment lastAccessed;   // 변경 가능 상태 (위험)
}
class ShipmentDao { Shipment get(Long id) { return null; } }
// 싱글톤 빈 필드:
// - 스레드 안전 객체 OK
// - 불변 OK
// - 변경 가능 상태 X

8.6 자기 점검 답변

빈에 ConcurrentHashMap 필드는 왜 OK인가?

:
1. 안전한 필드:

  • 스레드 안전 객체
  1. 왜 OK:

    • ConcurrentHashMap 내부 동기화
  2. 불변도 OK:

    • final 불변
  3. 위험:

    • 변경 가능 상태 X

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
getBean 100번?1객체 (싱글톤)
싱글톤 레지스트리?ApplicationContext
기본 싱글톤?명시 안 해도
왜 싱글톤?메모리/GC 효율
stateless?멀티스레드 공유
4주차 연결?인스턴스 상태 = 동시성
전통 vs Spring?getInstance vs 평범한 객체
ConcurrentHashMap?스레드 안전 (OK)
위험한 필드?변경 가능 상태
안전한 필드?불변, 스레드 안전

9.2 자기 점검 체크리스트

getBean 100번

  • 1객체

싱글톤 레지스트리

  • ApplicationContext

기본 싱글톤

  • 명시 X

왜 싱글톤

  • 메모리/GC

stateless

  • 멀티스레드

4주차 연결

  • 동시성

전통 vs Spring

  • 차이

안전한 필드

  • 스레드 안전/불변

9.3 추가 심화 질문

Q1: 싱글톤 빈에서 프로토타입 빈 사용?

답:

  • 싱글톤이 프로토타입 주입 시
  • 프로토타입도 1개로 고정 (의도와 다름)
  • ObjectProvider/Provider
  • @Lookup 메서드

Q2: ThreadLocal 과 싱글톤?

답:

  • 스레드별 상태
  • 싱글톤 빈에서 스레드별 데이터
  • 메모리 누수 주의 (remove)
  • 요청 스코프 대안

Q3: 싱글톤 빈 테스트?

답:

  • @SpringBootTest (컨텍스트)
  • 또는 직접 생성 (단위)
  • Mock 주입
  • 평범한 객체라 쉬움

Q4: 빈 스코프 종류?

답:

  • singleton (기본)
  • prototype
  • request/session/application (웹)
  • websocket

Q5: 싱글톤 동시성 보장?

답:

  • 컨테이너가 빈 1개 보장
  • 빈 내부는 개발자 책임
  • stateless 설계
  • 상태 필요 시 4주차 도구

🎯 핵심 요약 — 3줄 정리

1. 싱글톤 레지스트리

  • ApplicationContext 가 모든 빈을 기본 싱글톤으로 관리
  • getBean 100번 = 1객체 (서버 환경 메모리/GC 효율)

2. stateless 필수 (4주차 연결)

  • 싱글톤 빈은 여러 스레드가 공유 → 인스턴스 상태 = 동시성 문제
  • 상태 필요 시 4주차 도구 (Atomic/volatile/synchronized)

3. 전통 vs Spring + 안전한 필드

  • 전통 (getInstance, 테스트/DI 어려움) vs Spring (평범한 객체)
  • 불변·스레드 안전 객체 (ConcurrentHashMap) 필드는 OK

📚 다음으로...

Unit 8.4 — 의존관계 주입 DI ★깊이 (5주차 마지막!)

이번 Unit에서 싱글톤 레지스트리를 봤다면, 다음은 DI (★ 깊이 + 5주차 완주 + 종합 졸업 시험).

  • 런타임 의존관계 연결
  • 3가지 주입 (생성자✅/Setter/필드)
  • DI 와 IoC 관계
  • 생성자 주입 권장 이유
  • Phase 8 완주 + 5주차 전체 완주 + 종합 자기 점검 20문항

Phase 8 진행 상황

🌱 Phase 8 — Spring 컨테이너
  ✅ Unit 8.1 빈 팩토리와 ApplicationContext
  ✅ Unit 8.2 getBean()의 동작
  ✅ Unit 8.3 싱글톤 레지스트리 ★깊이 ← 여기
  ⏭ Unit 8.4 의존관계 주입 DI ★깊이 (5주차 완주!)

5주차 누적 진행

✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
  ✅ Phase 3~7 (15 Unit)
  🌱 Phase 8 — Spring 컨테이너 (3/4 진행)

총: 25/26 Unit (마지막 1개!)

★ 깊이 파기 — 싱글톤 레지스트리 (4주차 동시성 연결)

profile
Software Developer

0개의 댓글