[전통적인 방식] 사용자 코드가 Framework 코드를 호출
Car car = new Car();
//사용자코드가 라이브러리를 호출
car.turboDrive(); //호출
//라이브러리
//변하는 코드(new TruboEngine() -> new SuperEngine())
void turboDrive(){
engine = new TruboEngine();
engine.start();
...
}
[Ioc] Framework 코드가 사용자 코드를 호출
Car car = new Car();
car.drive(new SuperEngine());
//라이브러리가 사용자코드를 호출
//변하지 않는 코드
void drive(Engine engine) {
engine.start(); //호출
...
}
1) 수동 주입
Car car = new Car();
car.drive(new SuperEngine());
//라이브러리가 사용자코드를 호출
//변하지 않는 코드
//수동 주입
void drive(Engine engine) {
engine.start(); //호출
...
}
2) 자동 주입
Car car = new Car();
car.drive(new SuperEngine());
//자동 주입
@Autowired
void drive(Engine engine) {
engine.start();
...
}
인스턴스 변수(iv), setter, 참조형 매개변수를 가진 생성자, 메서드에 적용
알맞는 bean을 찾아서 넣어줌.
//@Autowired가 engine, doors에 자동 주입.
//생성자의 @Autowired는 생략 가능
//setter나 iv에 하나하나 직접 @Autowired를 붙이는 것 보다는
//생성자로 주입받도록 하는 것이 좋다.(주입받을 bean을 까먹을 수 있기 때문)
@Autowired
public Car(@Value("red") String color, @Value("100") int oil, Engine engine, Door[] doors) {
this.color=color;
this.oil=oil;
this.engine=engine;
this.doors=doors;
}
//@Autowired가 engine, doors에 자동 주입
@Autowired
public void setEngineAndDoor(Engine engine, Door[] doors) {
this.engine=engine;
this.doors=doors;
}
String container에서 "타입"으로 빈을 검색해서 참조 변수에 자동 주입(DI)
검색된 빈이 n개이면, 그 중에 참조변수와 "이름"이 일치하는 것을 주입.
주입 대상이 변수일 때, 검색된 빈이 1개 아니면 예외 발생.
주입 대상이 배열일 때, 검색된 빈이 n개라도 예외 발생X.
Class Car {
//검색된 engine이 3개. engine, turboEngine, superEngine
//참조변수와 이름이 일치하는 빈인 engine이 주입됨.
//변수는 반드시 빈이 1개여야 함.
@Autowired Engine engine;
//배열은 빈이 n개 OK.
@Autowired Engine[] engines;
//자동주입 X(superEngine = null)
//(required = false)면 빈이 0개도 OK. 예외발생X -> null.
@Autowired(required = false)
SuperEngine superEngine;
//("turboEngine")이 생략됨(첫글자 소문자를 name으로 함)
//배열 engines에 중복 주입OK.
@Component
class TurboEngine extends Engine {}
//배열 engines에 중복 주입OK.
@Component("engine")
class SuperEngine extends Engine {}
의존성 주입 실습
package com.fastcampus.ch3;
import org.springframework.beans.factory.annotation.*;
import org.springframework.context.*;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.*;
import org.springframework.stereotype.*;
import javax.inject.*;
import java.util.*;
@Component
@Scope("prototype")
class Door {}
@Component class Engine {}
@Component class TurboEngine extends Engine {}
@Component class SuperEngine extends Engine {}
@Component
class Car {
@Value("red") String color;
@Value("100") int oil;
// @Autowired
Engine engine;
// @Autowired
Door[] doors;
//생성자가 여러개 일때는 @Autowired쓰는 것을 권장
public Car() {}
// @Autowired
public Car(@Value("red") String color, @Value("100") int oil, Engine engine, Door[] doors) {
this.color = color;
this.oil = oil;
this.engine = engine;
this.doors = doors;
}
@Override
public String toString() {
return "Car{" +
"color='" + color + '\'' +
", oil=" + oil +
", engine=" + engine +
", doors=" + Arrays.toString(doors) +
'}';
}
}
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext ac = new GenericXmlApplicationContext("config.xml");
// Car car = ac.getBean("car", Car.class); // 타입을 지정하면 형변환 안해도됨. 아래의 문장과 동일
Car car = (Car) ac.getBean("car"); // 이름으로 빈 검색
System.out.println("car = " + car);
}
}