IoC 컨테이너: 객체를 생성하고 관계를 맺어주는 등의 작업을 담당하는 기능을 일반화한것
스프링의 IoC 컨테이너라고만 하면 의미가 모호해서 스프링이 제공하는 IoC 방식을 핵심을 짚어주는 의존 관계 주입 이라는 의도가 명확히 드러나는 이름을 사용하기 시작함.
의존관계란..
두 개의 클래스가 의존관게에 있다고 말할 떄는 방향을 부여해야한다.
UML 모델에서는 두 클래스의 의존관계를 다음과 같이 표현한다.
A 가 B에 의존하고 있다.
UserDao가 ConnectionMaker에 의존하고 있었다.
프로그램이 시작되고 UserDao 오브젝트가 만들어지고 나서 런타임시에 의존관계를 맺는 대상, 즉 실제 사용대상인 오브젝트를 의존 오브젝트(DConnectionMaker)라고 말한다.
의존관계 주입은 이렇게 구체적인 의존 오브젝트와 그것을 사용할 주체(클라이언트)를 런타임 시에 연결해주는 작업을 말한다.
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스만 의존하고 있어야한다.
- 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 걸졍한다.
- 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입) 해줌으로써 만들어진다.
런타임 시점의 의존관계를 결정하고 만드려면 제 3의 존재가 필요하다.
DaoFactory가 제3의 존재고 DI컨테이너다
의존관계를 맺는 방법이 외부로부터의 주입이 아니라 스스로 검색을 이용하는 방식 의존관계 검색
무엇을 사용할지 결정하지는 않고 능동적으로 찾기만한다.
의존관계 검색은 런타임 시 의존관계를 맵은 오브젝틀 결정하는 것과 오브젝트의 생성 작업은 외부 컨테이너에게 IoC 맡기지만, 이를 가져올떄는 메서드나 생성자를 통한 주입 대신 스스로 컨테이너에게 요청하는 방법을 사용한다,.
public UserDao(){
DaoFactory daoFactory = new DaoFactory();
// 스스로 DaoFactory(IoC Container) 에게 요청하는 것
this.connectionMaker = daoFactory.connectionMaker();
getBean()이라는 메소드가 의존관계 검색에 사용되는 것.
public UserDao(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
this.connectionMaker = context.getBean("connectionMaker", ConnectionMaker.class);
}
위 같이 앱 컨텍스트를 사용해서 의존관계 검샘색 방식으로 ConnectionMaker 오브젝트를 가져오게 할 수도 있따.
DI 는 주입받을 인스턴스와 주입 될 인스턴스 둘 다 빈으로 등록되어야 하는반면
DL(의존관계검색)은 검색하는 오브젝트는 스프링 빈일 필요가 없다.
코드에는 런타임 클래스에 대한 의존관계가 나타나지 않고, 인터페이스를 통해 결합도가 낮은 코드로 만들므로, 다른 책임을 가진 사용 ㅢ존관계에 있는 대상이 바뀌거나 변경되더라도 자신은 영향받지 않으며, 변경을 토안 다양한 확장방법에는 자유롭다.
만약 기존의 코드에서 DB 연결횟수를 세는 기능을 넣는다고 하면 DI를 통해 기존 코드를 최소한으로 수정해 넣을 수 있다.
카운트 세는 클래스를 하나 만든다
public class CountingConnectionMaker {
int counter = 0;
private ConnectionMaker connectionMaker;
public CountingConnectionMaker(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public Connection makeConnection() throws SQLException, ClassNotFoundException {
this.counter++;
return connectionMaker.makeConnection();
}
public int getCounter(){
return this.counter;
}
}
CountingConnectionMaker 도 Di를 받고 있따.
CountingConnectionMaker 의 오브젝트가 DI 받을 오브젝트도 역시 ConnectionMaker 인터페이스를 구현한 오브젝튿.
CountingConnectionMaker 가 추가되면서 바뀐 의존관계다.
이는 UserDao 가 기존에 ConnectionMaker 인터페이스에게만 의존하고 있었기 때문에 ConnectionMaker를 구현한 오브젝트라면 주입되는 객체가 바뀌어도 문제가 되지 않는다.
새로운 의존관계를 컨터이너가 사용할 설정 정보를 이용해 만들어보자, CountingDaoFactory 라는 이름으로 말이다.
여태까지는 생성라로 DI 해왔따.
생성자가 아닌 일반 메서드를 사용할 수도 있다.
스프링은 전통적으로 수정자 메서드를 가장 많이 사용해왔다. 왜나하면 설정코드로 XML을 사용하는 경우에는 자바빈 규약을 따라는 수정자 메서드가 가장 편하기 때문이다.
public class UserDao {
private ConnectionMaker connectionMaker;
public void setConnectionMaker(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
public class DaoFactory {
@Bean
public UserDao userDao(){
UserDao userDao = new UserDao();
userDao.setConnectionMaker(connectionMaker());
return userDao;
}