[스프링] IoC(제어 역전), DI(의존성 주입)
IoC(Inversion of Control ) : 제어 역전
- 프로그램 흐름을 제어하는 주체가 개발자에서 다른 프로그램으로 바뀜
- 스프링에서는 이 제어하는 주체가 스프링 컨테이너로 바뀜
DI(Dependency Injection) : 의존성 주입
- IoC 구현방법 중 하나 (DL 과 DI 가 있음)
- 객체가 다른객체에 의존하며 그 다른객체를 외부에서 생성해서 주입하는 것
① 의존성(Dependency)
- 한 객체가 다른 객체를 내부에서 사용함.
Class Battery {}
Class ElectronicToy {
private Battery battery;
ElectronicToy() {
battery = new battery();
}
}
→ ElectronicToy 클래스에서 Battery 클래스를 사용함 ☞ ElectronicToy 객체는 Battery 객체에 의존관계이다.
→ new 연산자를 통해 직접 객체를 만들고 있음.(강한 결합)
② 주입(Injection)
- 외부에서 객체를 생성해서 넣어 주는 것
1) ★ 생성자 주입
- 생성자 호출 시점에 1번만 실행된다
-
객체 주입을 강제하고 주입받은 객체의 불변성을 보장할 수 있다
- 장점
- 객체의 불변성을 보장할 수 있다
- 의존 관계의 변경은 거의 일어나지 않는다
- 의존관계를 설정하지 않으면 객체 생성이 불가해 컴파일시 체크할 수 있다
- 객체 생성시 순환참조를 탐지할 수 있다
- 테스트 코드 작성에 용이하다
Class Battery {}
Class ElectronicToy {
private Battery battery;
ElectronicToy(Battery battery) {
this.battery = battery;
}
}
→ battery 객체를 외부에서 생성해서 ElectronicToy 클래스에 생성자를 이용해 주입하고 있음.
2) setter 주입
- setter를 사용하여 언제든지 주입객체의 변경이 가능하다
Class Battery {}
Class ElectronicToy {
private Battery battery;
ElectronicToy() {}
public setBattery(Battery battery) {
this.battery = battery;
}
}
→ battery 객체를 외부에서 생성해서 ElectronicToy 클래스에 setter를 이용해 주입하고 있음.
3) 필드 주입
- 필드에 바로 주입하는 방법
- 스프링에서 권하지 않는다.
- 외부에서 접근이 불가능하다
- 하지만 테스트코드나
@Configuration
에서 특별한 용도로 사용 가능함
Class Battery {}
Class ElectronicToy {
@Autowired
private Battery battery;
}
4) 일반메서드 주입
- 한번에 여러 필드를 주입할 수 있다
- 스프링에서 권하지 않는다.
Class Battery {}
Class ElectronicToy {
private Battery battery;
@Autowired
public void init(Battery battery) {
this.battery = battery;
}
}
Spring 컨테이너
- 스프링 컨테이너 : 빈을 관리하는 컨테이너 (BeanFactory, ApplicationContext)
- 빈(Bean) : 스프링 컨테이너가 관리하는 클래스/객체
- ApplicationContext는 BeanFactory의 확장개념으로 이 자체가 스프링 컨테이너
- 스프링 컨테이너 생성과정
- 스프링 컨테이너 생성
- 스프링 빈 등록
- 스프링 빈 의존관계 설정
스프링 컨테이너는 클래스 간의 의존 관계를 미리 설정해 놓은 빈(Bean)설정 정보를 바탕으로 컨테이너가 의존주입을 한다
- 개발자들은 빈 설정파일(=스프링컨테이너)에서 의존관계 정보를 입력함
- 객체 레퍼런스를 컨테이너로부터 주입 받아서, 실행 시에 동적으로 의존관계가 생성
-
컨테이너가 흐름의 주체가 되어 어플리케이션 코드에 의존 관계를 주입
- 빈을 만들고 빈 사이의 의존성을 엮어주며 그 빈을 제공해줌
- 의존성 주입은 스프링 컨테이너의 빈 끼리만 가능
의존주입 어노테이션
- 의존관계 주입을 하는 어노테이션
- setter역할을 하기 때문에 setter가 필요 X
- 생성자가 아닌 속성과 메서드에 사용시 디폴트생성자가 꼭 있어야함.
@Autowired
- 객체의 타입이 일치하는 객체 자동 주입
- 생성자, 속성, 메서드에 모두 사용 O
ex) WordRegisterService.java
public class WordRegisterService {
private WordDao wordDao;
@Autowired
public WordRegisterService(WordeDao wordDao) {
this.wordDao = wordDao;
}
}
@Resource
- 객체의 이름이 일치하는 객체 자동 주입(id or name)
- 속성, 메서드에 사용 O, 생성자에는 사용 X
※ 동일 객체가 2개 이상일 경우 자동 주입 객체를 판단 못하면 Exception 발생.
-> @Resource대신 @Autowired를 사용하기 위해서는 @Qualifier 사용(value를 이용하여 id부여해준다고 생각)
ex) WordRegisterService.java
public class WordRegisterService {
//둘 중 택1
@Resource(name="wordDao1")
private WordDao wordDao;
@Autowired
@Qualifier("usedDao")
private WordDao wordDao;
public WordRegisterService(WordeDao wordDao) {
this.wordDao = wordDao;
}
}