# 1. Object and relation

## IOC 컨테이너와 DI의 차이점 정리

IoC 컨테이너는 **객체의 생성과 생명주기, 그리고 객체 간 관계 설정에 대한 제어권을 애플리케이션 코드로부터 가져가는 주체**입니다. \
기존 구조에서는 각 클래스나 `main()` 코드가 어떤 객체를 만들고, 언제 만들며, 어떤 구현체를 사용할지까지 직접 결정했습니다. \
반면 IoC 컨테이너가 도입되면 객체는 더 이상 자신이 사용할 의존 객체를 생성하거나 선택하지 않고, 컨테이너가 미리 정의된 설정 정보를 바탕으로 객체를 생성하고 관리합니다. \
이로 인해 객체는 자신이 싱글톤인지, 언제 생성되는지, 어떤 순서로 초기화되는지조차 알 필요가 없으며, 오직 자신의 책임과 역할에만 집중할 수 있게 됩니다.

DI는 이러한 IoC가 **구체적인 코드 구조로 드러나는 방식**입니다. 의존관계 주입이란 객체가 필요로 하는 의존 대상을 직접 만들지 않고, 생성자나 메서드를 통해 외부에서 전달받는 것을 의미합니다. \
DI 자체는 객체를 “어떻게 생성하느냐”보다 “의존관계를 누가 결정하고 연결하느냐”에 초점을 둡니다. \
IoC 컨테이너는 DI를 수행하는 실행 주체이고, DI는 IoC를 구현하는 핵심 메커니즘이라고 볼 수 있습니다.&#x20;

즉, **IoC는 제어권 이동이라는 상태를 설명하는 개념이고, DI는 그 상태를 실제 코드로 구현하는 방법**입니다.

### 1.1. 초기 구현

UserDao는 JDBC API를 직접 사용하여 사용자 정보를 등록(add)하고 조회(get)합니다.

문제점:

* DB 연결 생성 코드가 add, get 메서드에 중복됨
* DB 종류, 접속 방식, 드라이버 변경 시 여러 메서드를 동시에 수정해야 함
* 데이터 접근 로직과 DB 연결 로직이 하나의 클래스에 섞여 있음

변경에 취약한 구조

### 1.2. 관심사 분리

관심사를 분리할 수 있는 구조이고,

* 사용자 데이터를 SQL로 다루는 책임
* DB 커넥션을 생성하는 책임

DB 커넥션 생성부분을 별도의 메서드로 추출.

### 1.3. 상속을 통한 확장

getConnection()을 추상 메서드로 만들고, UserDao를 상속한 NUserDao, DUserDao에서 DB 커넥션 생성 방식을 따로 구현.

이로 인해:

* UserDao는 수정 불필요
* DB 연결 방식만 서브클래스로 확장이 가능

But,

* 동일한 DB 커넥션 로직을 재사용하기 어려움

상속이 아닌 다른 확장 방식이 필요.

#### 클래스 분리

별도의 클래스 SimpleConnectionMaker로 DB 커넥션 생성 책임을 분리하여 UserDao가 해당 클래스를 필드로 사용.

But,

* UserDao가 특정한 구현 클래스에 의존하게 됨
* DB 연결 방식을 바꾸려면 UserDao를 수정해야함.

결국, 독립성은 확보되지 않음

#### 인터페이스 도입

ConnectionMaker 인터페이스를 도입하여 독립성을 확보

* UserDao는 ConnectionMaker 인터페이스에만 의존
* NConnectionMaker, DConnectionMaker에서 구현

UserDao 입장에서는 DB 연결이 어떻게 되는지 모르게 됨.

### 1.4. 제어의 역전(IoC)

객체 생성과 사용에 대한 제어권을 애플리케이션 코드에서 분리해 외부로 이동시키는 설계 개념.\
객체 팩토리를 도입하면 생성 책임과 사용 책임이 분리되어, 결합도가 낮아집니다.

#### 1.4.1. 오브젝트 팩토리

**문제점: 테스트 코드가 테스트 목적 외에 객체 생성 책임까지 갖고 있는 문제**

기존구조에서는 `UserDaoTest`가 `UserDao` 생성과 동시에 어떤 `ConnectionMaker`를 사용할지 직접 결정하고 있었습니다.\
UserDao는 데이터 접근 로직이고, `ConnectionMaker` 선택 / 객체 생성은 관심사가 아님.

**해결책: 객체 생성을 전담하는(오브젝트팩토리)를 도입하여, 객체 생성은 오브젝트 팩토리가 결정하고, 만들어진 객체를 제공만 하게됩니다.**

오브젝트 팩토리의 역할:&#x20;

* 객체 생성 책임
* 구현 클래스 선택 로직 제거
* 변경 지점을 한 곳으로 모음

<figure><img src="https://2804243633-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfV6clXG953LqFieNgWUf%2Fuploads%2FOnG3B7BgigdhXzQlh1BY%2Fimage.png?alt=media&#x26;token=2f8096be-d084-4817-bdfc-e0bb6568a6cd" alt=""><figcaption></figcaption></figure>

```kotlin
class DaoFactory {
    fun userDao(): UserDao {
        val connectionMaker = DConnectionMaker()
        return UserDao(connectionMaker)
    }
}
```

`UserDaoTest`는 `ConnectionMaker` 구현 클래스에 대해 알 필요가 없어지고, 어떻게 만들어졌는지 관심이 없어집니다.

#### 1.4.2. 오브젝트 팩토리의 활용

`DaoFactory`가 여러 DAO를 생성하게 되면, 중복 코드가 발생.\
각 DAO 생성 메서드마다 new `ConnectionMaker()`가 반복.

<figure><img src="https://2804243633-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfV6clXG953LqFieNgWUf%2Fuploads%2FAhd4Jp9zNpoRfFP5xRps%2Fimage.png?alt=media&#x26;token=16dd8780-1ed1-4c3d-a9b2-fc0d27d6484d" alt=""><figcaption></figcaption></figure>

중복 문제는 분리를 하는것이 가장 좋은 방법이기 떄문에, `ConnectionMaker`의 구현 클래스를 결정하고 오브젝트를 만드는 코드를 별도의 메서드로 분리.

```kotlin
class DaoFactory {

    fun userDao(): UserDao {
        return UserDao(connectionMaker())
    }

    fun accountDao(): AccountDao {
        return AccountDao(connectionMaker())
    }

    fun messageDao(): MessageDao {
        return MessageDao(connectionMaker())
    }

    private fun connectionMaker(): ConnectionMaker {
        return DConnectionMaker()
    }
}
```

변경된 구조에서는 DB 연결 방식 변경시 `connectionMaker` 메서드만 수정하면 됩니다. DAO 갯수가 늘어나도 변경 범위는 최소화됩니다.

**`UserDao, ConnectionMaker`: 애플리케이션의 핵심 로직을 담당하는 컴포넌트**\
\&#xNAN;**`DaoFactory`: 위 컴포넌트들을 어떻게 조합할지 결정하는 설계 요소.** 객체들의 관계와 의존 방향을 쉽게 파악할 수 있는 위치가 됩니다.

#### 1.4.3. 제어권 이전을 통한 제어관계 역전

기존 구조에서는 `UserDao`가 어떤 `ConnectionMaker` 구현을 사용할지 스스로 결정헀지만, 팩토리를 도입한 후에는 **결정권이 `DaoFactory`로 이동됩니다.**

* 객체 생성 시점
* 객체 간 의존 관계
* 어떤 구현체를 사용할지에 대한 결정

#### IoC와 프레임워크

IoC는 계 원칙이고, 이를 자동화하고 확장한 것이 스프링과 같은 IoC 컨테이너입니다.\
라이브러리: 애플리케이션 코드라 흐름을 제어\
프레임워크: 흐름을 주도하고 애플리케이션 코드는 그 안에서 호출.

정리하면, 스프링은

* 객체 생성
* 의존 관계 설정
* 생명 주기 관리

를 모두 담당하는 IoC 컨테이너를 제공합니다.

### 1.5. 스프링의 IoC

`@Configuration, @Bean`은 자바 코드 기반 설정정보 역할을 수행.\
스프링 IoC는 객체 생성, 관계 설정, 다양한 IoC 서비스를 제공

#### 1.5.1. 오브젝트 팩토리를 이용한 스프링 IoC

Bean 이란, IoC 방식으로 관리되는 객체를 의미. Bean Factory는 Bean을 생성하고 관계를 설정하는 핵심 IoC 객체. Application Context는 Bean Factory를 확장한 IoC 엔진으로 이해하면 됩니다.

애플리케이션 컨텍스트의 역할:

* Bean 생성
* Bean 간 의존 관계 설정
* Bean 사용 시점 제어
* 설정정보 기반으로 전체 애플리케이션 구조 관리

**스프링 설정 정보로 변환한 DaoFactory**

```kotlin
@Configuration
class DaoFactory {

    @Bean
    fun userDao(): UserDao {
        return UserDao(connectionMaker())
    }

    @Bean
    fun connectionMaker(): ConnectionMaker {
        return DConnectionMaker()
    }
}

```

* `@Configuration`은 해당 클래스가 설정정보라는 것을 나타냅니다.
* `@Bean`은 메서드의 반환 객체를 스프링 빈으로 등록합니다.

**Application Context 사용**

```kotlin
fun main() {
    val context = AnnotationConfigApplicationContext(DaoFactory::class.java)
    val userDao = context.getBean("userDao", UserDao::class.java)
}
```

`getBean`은 애플리케이션 컨텍스트에 빈을 요청하는 메서드입니다.\
UserDao는 `@Bean` 메서드 이름이 빈 이름이 되었고, 타입을 함께 지정하면 캐스팅 부담을 제거할 수 있습니다.

#### 1.5.2. 애플리케이션 컨텍스트의 동작방식

애플리케이션 컨텍스트는 설정정보를 분석해 빈 목록을 구성합니다. 이후, 클라이언트가 `getBean`을 호출하면 아래 흐름으로 동작합니다.

1. 설정 정보에서 Bean 메타정보 로딩
2. Bean 이름과 타입으로 Bean 검색
3. Bean 생성 메서드 호출
4. 생성된 객체를 클라이언트에 반환

`DaoFactory`를 직접 사용하는 방식과 비교하면 제어권이 완전히 Application Context로 이동했고, 클라이언트는 어떤 팩토리를 사용하는지 알 필요가 없어집니다. 오로지 Application Context만 의존합니다.

**Application Context 사용시 장점**

클라이언트는 구체적인 팩토리 클래스를 알 필요가 없게 되며, 팩토리 구현이 바뀌어도 클라이언트 코드는 변경되지 않습니다.

**IoC 서비스의 확장**

객체 생성뿐만 아니라,

* 자동 의존성 주입
* Bean 후처리
* 라이프사이클 관리

같은 기능들을 함께 제공합니다.

**다양한 Bean 검색 방식**

* 이름 기반
* 타입 기반
* 특정 어노테이션 기반 검색이 가능

#### 1.5.3. 스프링 IoC 용어 정리

**Bean**: 스프링 IoC 컨테이너가 생성하고 관리하는 객체.

**Bean Factory**: 빈을 생성하고 관리하는 IoC 컨테이너의 핵심 인터페이스. `getBean` 메서드 제공

**Application Context**: `BeanFactory`를 확장한 IoC 컨테이너. Bean 관리 외에 애플리케이션 전반을 지원하는 기능을 포함

**Configuration Metadata:** IoC 컨테이너가 Bean을 생성하고 관계를 설정하는 데 사용하는 정보. 자바 코드, XML, 어노테이션 형태로 제공.

**컨테이너 / IoC 컨테이너:** Bean을 관리하는 주체. 스프링에서는 Application Context를 의미합니다.

**Spring Framework:** IoC 컨테이너와 애플리케이션 컨텍스트를 중심으로 다양한 기능을 제공하는 종합 프레임워크.

### 1.6. 싱글톤 레지스트리와 오브젝트 스코프

스프링 Application Context는 단순히 오브젝트 팩토리가 아니라, 싱글톤을 관리하는 싱글톤 레지스트리의 역할을 수행합니다. 스프링 빈은 기본적으로 싱글톤 스코프로 생성됩니다.

`DaoFactory`를 직접 사용하든, 스프링 애플리케이션 컨텍스트를 사용하든 테스트 결과만 보면 동일해보이지만, 차이가 있습니다. `DaoFactory`에서 `userDao()`를 여러 번 호출해 얻은 객체와, Application Context에서 `getBean("userDao")`로 얻은 객체가 동일한 객체인가?

* 동일성: Identity. 두 변수가 완전히 같은 객체 인스턴스를 가치킴
* 동등성: Equality. 서로 다른 객체이지만 내부 값이 같음.

(DaoFactory에서 userDao()를 두번 호출하면 new 키워드로 인해 매번 새로운 객체가 생성됩니다.)

#### 1.6.1. 싱글톤 레지스트리로서의 애플리케이션 컨텍스트

ApplicationContext를 사용해 getBean`("userDao")`를 두 번 호출하면 항상 동일한 UserDao 인스턴스가 반환됩니다. 이는 스프링 애플리케이션 컨텍스트가 빈을 싱글톤으로 관리하는 싱글톤 레지스트리이기 때문입니다(기본 설정).

서버 환경에서 다수의 클라이언트의 요청을 동시에 처리해야할때, 객체를 매번 새로 생성하게 되면:

* 객체 생성 비용 증가
* GC 부하 증가
* 메모리 사용 급증

과 같은 문제점 발생

전통적인 싱글톤 패턴의 한계

```kotlin
class UserDao private constructor(
    private val connectionMaker: ConnectionMaker
) {
    companion object {
        private var INSTANCE: UserDao? = null

        @Synchronized
        fun getInstance(connectionMaker: ConnectionMaker): UserDao {
            if (INSTANCE == null) {
                INSTANCE = UserDao(connectionMaker)
            }
            return INSTANCE!!
        }
    }
}
```

문제점:

* private 생성자로 인해 상속 불가
* 테스트 시 대체 객체 주입이 어려움
* 전역 상태에 의존하게 되어 설계가 경직됨
* 멀티 JVM 환경에서는 싱글톤 보장이 불완전함.

이로 인해 싱글톤 패턴은 안티 패턴으로 불리기도 합니다.

**싱글톤 레지스트리의 장점**

스프링은 싱글톤 패턴을 객체 내부가 아닌 IoC 컨테이너 차원에서 관리합니다. 이를 통해:

* public 생성자 사용 가능
* 상속과 다형성 유지
* 테스트 시 자유로운 객체 대체
* 객체 생성과 생명주기 제어를 컨테이너에 위임

이 간으해집니다. 객체는 싱글톤인지 여부를 전혀 알 필요가 없어집니다.

#### 1.6.2. 싱글톤고다 오브젝트의 상태

싱글톤 빈은 여러 스레드가 동시에 접근하기 때문에 상태 관리에 주의해야합니다.\
싱글톤 빈이 인스턴스 변수를 통해 상태를 저장하면 동시성 문제가 발생. 그렇기에 항상 stateless 방식으로 설계해야합니다.

* 변경 가능한 값은 메서드 로컬 변수로 사용
* 요청별 데이터는 파라미터로 전달
* 인스턴스 변수는 공유되어도 안전한 읽기 전용 데이터만 허용

`ConnectionMaker`와 같이, 변경되지 않는 의존 객체는 인스턴스 변수로 보관해도 문제가 없습니다.

#### 1.6.3. 스프링 빈의 스코프

* Singleton: 컨테이너 내에서 하나의 인스턴스만 생성. 기본 스코프
* Prototype: 빈 요청 시마다 새로운 객체 생성
* request: Http 요청 하나당 하나의 빈 생성
* session: Http 세션당 하나의 빈 생성

### 1.7. 의존관계 주입(DI)

의존관계 주입은 IoC 개념을 구체적인 설계와 구현 방식으로 명확히 드러낸 핵심 메커니즘.\
객체는 자신이 사용할 의존 객체를 직접 생성하지 않고, 외부에서 주입받아서 사용.\
의존 관계를 인터페이스에 의존하도록 설계하면 결합도가 낮아지고 변경에 유연해집니다.\
스프링 IoC컨테이너는 의존 관계 설정과 주입을 전당하는 DI 컨테이너 역할을 수행함.

#### 1.7.1. 제어의 역전(IoC)과 의존관계 주입

IoC는 제어권이 객체 자신에게 있지 않고 외부로 넘어간 상태를 의미하지만, 이 개념만으로는 스프링이 제공하는 핵심 기능을 구체적으로 설명하기 어렵습니다.\
그래서 스프링에서는 객체간 관계를 어떻게 맺고 전달하는지를 강조하기 위해 의존 관계 주입(DI) 용어를 사용.

DI는:

* 어떤 객체가
* 어떤 다른 객체에 의존하고
* 그 의존 객체를 누가, 언제, 어떻게 전달하는가

를 명확히 드러내는 개념점

#### 1.7.2. 런타임 의존관계 설정

의존관계는 항상 방향성을 가지고, A가 B를 사용하면 A는 B에 의존한다고 표현합니다.\
여기서 중요한 점은, 설계 시점의 의존 관계와 런타임 시점의 의존 관계가 다를 수 있습니다.

`UserDao`는 `ConnectionMaker` 인터페이스에만 의존하고, 구체적인 구현 클래스가 무엇인지는 코드에서 드러나지 않습니다.\
런타임에 실제 어떤 구현 객체를 사용할지는 제3의 존재가 결정하고, 이 역할을 수행하는 것이 `DaoFactory`, 그리고 스프링 IoC 컨테이너입니다.

DI가 성립하기 위한 조건:

* 클래스 코드에는 인터페이스에만 의존해야 합니다.
* 구체적인 의존 객체 선택은 외부에서 이루어져야 합니다.
* 의존 객체는 생성자나 메서드를 통해 전달되어야 합니다.

**UserDao의 의존관계 주입 예제 (생성자 주입)**

```kotlin
class UserDao(
    private val connectionMaker: ConnectionMaker
)
```

`UserDao`는 `ConnectionMaker` 구현체를 알 필요가 없어지고, 오직 인터페이스 규약만 알고 사용합니다.

#### 1.7.3. 의존관계 검색과 주입

DI와 유사하지만 다른 방식으로 의존관계 검색(Dependency Lookup)이라는 방식도 존재합니다.\
의존관계 검색은 객체가 스스로 컨테이너에게 필요한 의존 객체를 요청하는 방식입니다.

```kotlin
class UserDao {
    private val connectionMaker: ConnectionMaker

    init {
        val context = AnnotationConfigApplicationContext(DaoFactory::class.java)
        this.connectionMaker = context.getBean(
            "connectionMaker",
            ConnectionMaker::class.java
        )
    }
}
```

전체 흐름:

* AnnotationConfigApplicationContext 생성
* DaoFactory 클래스 스캔
* `@Configuration` 확인
* `@Bean` 메서드 실행
* 반환된 객체를 Bean으로 등록
* 이후 getBean()으로 꺼내 쓸 수 있음음

AnnotationConfigApplicationContext

* Spring Framework의 IoC 컨테이너 구현체
* `@Configuration, @Bean` 같은 어노테이션 기반 설정을 읽는 컨테이너
* 객체 생성, 의존성 주입, 생명주기 관리 담당

`DaoFactory::class.java`

* 설정 클래스

```kotlin
@Configuration
class DaoFactory {
    @Bean
    fun connectionMaker(): ConnectionMaker {
        return DConnectionMaker()
    }
}
```

이 클래스 안의 @Bean 메서드들을 읽어서 객체를 생성하고 컨테이너에 등록합니다.

위 방식은 객체가 스프링 API에 의존하게 된다는 단점이 있습니다.\
따라서, 일반적인 애플리케이션 코드에서는 의존관계 주입 방식을 사용하는 것이 바람직합니다.

#### 1.7.4. 의존관계 주입의 응용

DI를 적용하면 구현 교체가 쉬워집니다. \
예를 들어, 개발 환경에서는 로컬 DB를, 운영환경에서는 운영 DB를 사용해야하는 경우 DAO 코드는 전혀 수정하지 않고 설정정보만 변경해 해결할 수 있습니다. \
(부가 기능을 가진 객체를 중간에 끼워 넣는것도 가능)

`ConnectionMaker`를 감싸는 `CountingConnectionMaker`를 주입하면 DB 커넥션 사용 횟수 측정 같은 기능을 손쉽게 추가할 수 있습니다.

```kotlin
class CountingConnectionMaker(
    private val realConnectionMaker: ConnectionMaker
) : ConnectionMaker {
    private var counter: Int = 0
    
    override fun makeConnection(): Connection {
        counter++
        return realConnectionMaker.makeConnection()
    }

    fun getCounter(): Int {
        return counter
    }
}
```

#### 1.7.5. 메서드를 이용한 의존관계 주입

의존관계 주입은 생성자만으로 이루어지지 않습니다. 수정자 메서드`(setter)`를 통한 주입도 가능합니다.

**수정자 메서드 DI 예시**

```kotlin
class UserDao {
    private lateinit var connectionMaker: ConnectionMaker

    fun setConnectionMaker(connectionMaker: ConnectionMaker) {
        this.connectionMaker = connectionMaker
    }
}
```

이 방식은:

* 선택적인 의존관계
* 변경 가능성이 있는 의존 관계

에 적합합니다.

팩토리 설정 코드에서는 아래와 같이 사용합니다.

```kotlin
@Bean
fun userDao(): UserDao {
    val userDao = UserDao()
    userDao.setConnectionMaker(connectionMaker())
    return userDao
}
```

생성자 주입과 수정자 주입은 주입 시점과 의도를 기준으로 선택.

### 1.8. XML을 이용한 설정

코드 기반 설정`(@Configuration, @Bean)`은 DI 구조를 명확히 표현할 수 있지만 설정 변경 시 컴파일이 필요.\
XML 설정은 DI 정보를 순수 설정 파일로 분리해 코드 변경 없이 의존관계를 교체할 수 있게 해줍니다.\
스프링 애플리케이션 컨텍스트는 자바 설정과 XML 설정을 동일한 IoC 메타데이터로 취급.\
**따라서, XML 설정은 빈 정의, 의존관계 주입, 값 주입까지 모두 표현이 가능합니다**

#### 1.8.1. XML 설정

XML 설정의 루트 엘리먼트는 `<Beans>` 이며 각 \<Bean> 태그 하나가 하나의 빈 정의에 해당. 자바 설정과 XML 설정의 핵심 정보는 동일합니다.

빈 정의에 포함되는 정보:

* 빈 이름
* 빈 클래스
* 의존 객체 정보

자바 설정에서의 대응 관계는 아래와 같습니다.

자바 설정 <--> XML 설정 개념 대응

* @Configuration <--> `<beans>`
* @Bean 메서드 이름 <--> `<bean id="">`
* return new Xxx() <--> <kbd>`<bean class="">`</kbd>

**ConnectionMaker() 빈의 XML 전환**

```kotlin
@Bean
fun connectionMaker(): ConnectionMaker {
    return DConnectionMaker()
}
```

XML 설정으로 변환

```xml
<bean id="connectionMaker"
      class="springbook.user.dao.DConnectionMaker" />
```

XML에서는

* 메서드 개념이 없고
* 클래스 이름을 직접 지정

따라서 패키지를 포함한 클래스 전체 이름을 정확히 작성해야 합니다.

**UserDao() 빈의 XML 전환**

```kotlin
userDao.setConnectionMaker(connectionMaker)
```

UserDao는 ConnectionMaker에 의존함. XML에서는 `<property>` 태그를 사용해 의존관계를 표현.

```xml
<bean id="userDao"
      class="springbook.user.dao.UserDao">
    <property name="connectionMaker" ref="connectionMaker" />
</bean>
```

* name: 주입 대상 프로퍼티 `이름. setConnectionMaker()`에 대응
* ref: 주입할 다른 빈의 이름

XML 기반 DI 설정 전체 예시

```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="connectionMaker"
          class="springbook.user.dao.DConnectionMaker" />

    <bean id="userDao"
          class="springbook.user.dao.UserDao">
        <property name="connectionMaker" ref="connectionMaker" />
    </bean>
</beans>
```

#### 1.8.2. XML을 이용하는 애플리케이션 컨텍스트

XML 설정을 사용하는 애플리케이션 컨텍스트는 `GenericXmlApplicationContext` 또는 `ClassPathXmlApplicationContext`를 사용합니다.

```kotlin
fun main() {
    val context =
        ClassPathXmlApplicationContext("applicationContext.xml")

    val userDao = context.getBean("userDao", UserDao::class.java)
}
```

XML 파일은 보통 `applicationContext.xml` 이름으로 만들고, 클래스패스 루트 또는 지정한 패키지에 위치합니다.

#### 1.8.3. DataSource 인터페이스로 전환

ConnectionMaker는 DB 커넥션을 하나 만들어주는 단순한 인터페이스. 실제 스프링 환경에서는 표준 JDBC 추상화 인터페이스인 DataSource를 사용합니다.

**UserDao는 DataSource에 의존하도록 변경**

```kotlin
class UserDao {
    private lateinit var dataSource: DataSource

    fun setDataSource(dataSource: DataSource) {
        this.dataSource = dataSource
    }

    fun add(user: User) {
        val connection = dataSource.getConnection()
        // JDBC 로직
    }
}
```

**XML에서 DataSource 설정**

```xml
<bean id="dataSource"
      class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost/springbook" />
    <property name="username" value="spring" />
    <property name="password" value="book" />
</bean>

<bean id="userDao"
      class="springbook.user.dao.UserDao">
    <property name="dataSource" ref="dataSource" />
</bean>
```

* ref는 다른 빈을 주입할 때 사용
* value는 문자열, 숫자 같은 단순 값을 주입할 때 사용
* 스프링은 문자열 값을 자동으로 적절한 타입으로 변환합니다.

**XML 설정의 장점**

* 자바 코드 수정 없이 설정 변경 가능.
* 환경별 설정 분리 용이
* 컴파일 없이 DI 구조 변경 가능
* 운영 환경에서 설정 관리 유리

But,

* 클래스 이름을 문자열로 관리해야 하고,
* 리팩토링 시 IDE 지원이 제한적입니다.

**정리**\
XML 설정은 DI 정보를 코드에서 완전히 분리하는 방식.\
스프링은 자바 설정과 XML 설정을 동일한 IoC 메타데이터로 처리.\
XML을 사용하면 환경 변화와 설정 변경에 더 유연하게 대응 가능.\
실무에서는 자바 설정과 XML 설정을 상황에 맞게 혼용해 사용하면 좋습니다.
