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번만 실행된다
  • 객체 주입을 강제하고 주입받은 객체의 불변성을 보장할 수 있다

  • 장점
    1. 객체의 불변성을 보장할 수 있다
    • 의존 관계의 변경은 거의 일어나지 않는다
      1. 의존관계를 설정하지 않으면 객체 생성이 불가해 컴파일시 체크할 수 있다
      2. 객체 생성시 순환참조를 탐지할 수 있다
      3. 테스트 코드 작성에 용이하다
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의 확장개념으로 이 자체가 스프링 컨테이너
  • 스프링 컨테이너 생성과정
    1. 스프링 컨테이너 생성
    2. 스프링 빈 등록
    3. 스프링 빈 의존관계 설정

스프링 컨테이너는 클래스 간의 의존 관계를 미리 설정해 놓은 빈(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;
    }
    
}