객체 간의 의존 관계를 개발자가 아닌 스프링 컨테이너(IOC 컨테이너) 가 관리하고 주입해주는 설계 패턴
스프링의 핵심 개념인 제어의 역전(Inversion of Control, Ioc) 의 구현 방식 중 하나
1) 생성자 주입(Constructor Injection)
@Autowired를 붙여 의존성을 주입받을 수 있다.@Autowired를 생략 할 수 있다.@Component
public class Service {
private final Repository repository;
// 생성자를 통한 의존성 주입
@Autowired
public Service(Repository repository) {
this.repository = repository;
}
}
2) Setter 주입(Setter Injection)
@Component
public class Service {
private Repository repository;
// Setter를 통한 의존성 주입
@Autowired
public void setRepository(Repository repository) {
this.repository = repository;
}
}
3) 필드 주입(Field Injection)
@Autowired 어노테이션을 붙여주면 자동으로 의존성 주입이 된다.)@Component
public class Service {
@Autowired
private Repository repository;
}
1) XML 기반 설정
applicationContext.xml파일을 통해 설정<bean id="service" class="com.example.Service"> <property name="repository" ref="repository" /> </bean> <bean id="repository" class="com.example.Repository" />
2) Java Config 기반 설정
Java 클래스에서
@Configuration과@Bean으로 설정@Configuration public class AppConfig { @Bean public Service service() { return new Service(repository()); }
@Bean
public Repository repository() {
return new Repository();
}
}
3) Annotation 기반 설정
> `@Component`와 `@Autowired`를 활용
```java
@Component
public class Repository {}
@Component
public class Service {
private final Repository repository;
@Autowired
public Service(Repository repository) {
this.repository = repository;
}
}
Spring Framework reference에서 권장하는 방법은 생성자를 통한 주입이다.
필수적으로 사용해야하는 의존성 없이는 Instance를 만들지 못하도록 강제할 수 있기 때문이다.
- 순환 참조를 방지할 수 있다.
∘ 의존 관계에 내용을 외부로 노출 시킴으로써 컴파일 시점에 오류를 체크할 수 있따.- 불변성을 유지한다.
∘ 생성자로 의존성을 주입할 때 final로 선언할 수 있고, 이로 인해 런타임에서 의존성을 주입받는 객체가 변할 일이 없어진다.
∘ 그래서 누군가 Controller 내부에서 Service 객체를 바꿔치기 할 수 없다.- 테스트에 용이하다.
∘ DI의 핵심은 관리되는 클래스가 DI 컨테이너에 의존성이 없어야 한다.
∘ 메인 코드가 필드 주입으로 작성된 경우, 순수 자바 코드로 단위 테스트를 실행하는 것은 불가능하다.
∘ 메인 코드는 Spring 같은 DI 프레임워크 위에서 동작하지만, 테스트 코드는 그렇지 않아서 의존관계 주입이 null 상태여서 NullPointError이 발생한다.
∘ 즉, 독립적으로 인스턴스화가 가능한 POJO(Plain Old Java Object)여야 한다는 것이다.