IoC 컨테이너 : @Autowired
@Autowired
필요한 의존 객체의 Type에 해당하는 빈을 찾아 주입한다.
1. @Autowired
- required : 기본값은 true 따라서 의존 객체가 빈으로 등록되지 않으면 애플리케이션 구동이 실패한다. 하지만 false로 둘 경우 의존성 없이도 실행가능 (빈으로 등록이 가능)
사용가능한 위치
- 생성자
- 생성자를 통해 주입을 받는 경우는 빈을 생성할 때에도 (인스턴스를 생성할 때에도) 개입이 되기 때문에 파라미터로 넘겨진 타입의 빈이 (의존 객체가) 없으면 인스턴스를 만들지 못한다. 다른 두 방법에 비해 명시적이고 오류를 발견하기 쉽다.
- 즉, 의존관계를 주입하지 않은 경우 인스턴스를 생성할 수 없기 때문에 의존 관계에 대한 내용이 외부로 노출되어 컴파일타임에 에러를 발견할 수 있다.
- final 키워드를 사용할 수 있다 : 빈으로 등록할 객체 내부에서 의존관계에 있는 객체를 바꿔치기 할 수 없다.
- 스프링 4.3 부터는 생성자가 하나일 경우 생략이 가능하다.
@Service public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } }
- Setter
- Field
Setter 방식과 Field 방식은 일반적으로는 의존 객체가 빈으로 등록되있지 않으면 에러를 발생시키지만, 의도적으로 @Autowired(required = false) 옵션을 준다거나 인위적으로 의존관계의 객체가 생성이 되지 않은 상태에서도 동작하게 할 경우 해당 빈의 인스턴스는 생성되므로 NullPointerException의 에러를 발생시킬 수 있다.
즉, 의존성 주입이 필요한 객체가 주입되지 않아도 얼마든지 인스턴스를 생성할 수 있다는 것이 문제이다.
@Service public class UserService { private final UserRepository userRepository; @Autowired(required = false) public void setUserService(UserRepository userRepository) { this.userRepository = userRepository; } }
생성자를 통한 주입의 장점
- 의존관계가 설정되지 않으면 객체를 생성할 수 없다 : 컴파일 타임에 에러발견 가능 + NullPointerException 방지
- 의존 객체를 final로 선언할 수 있다 : Immutable
- 순환참조 감지 : 컨테이너가 빈을 생성하는 시점에 순환참조가 발생하면 앱 구동이 실패
- 테스트코드 작성이 용이하다
2. 컨테이너에서 주입하려는 빈이 여러개 존재할 경우
- 해당 타입의 빈이 없는 경우 : 인스턴스 생성 불가능
- 해당 타입의 빈이 한 개인 경우 : 인스턴스 생성 가능
- 해당 타입의 빈이 여러개인 경우
- 빈 이름으로 시도
- 같은 이름의 빈을 찾으면 해당 빈을 사용 : 인스턴스 생성 가능
- 같은 이름의 빈을 찾지 못하면 실패 : 인스턴스 생성 불가능
일반적으로 해당 타입의 빈이 여러개인 경우 스프링은 사용자가 원하는 것이 무었인지 모르기 때문에 의존성 주입이 불가능하다. 이를 해결하기 위한 방법으로 3가지가 있다.
- @Primary : 주로 사용하고 싶은 빈이 무었인지 마킹한다. @Qualifier 방식보다 추천
- 해당 타입의 빈을 모두 주입받는다.
- @Qualifier : 사용하고 싶은 빈을 마킹한다. @Qualifier("name")
@Service public class BookService { @Autowired List<BookRepository> bookRepositories; }
모든 빈을 주입받는 경우 위의 코드와 같이 List 를 사용해서 넘겨받을 수 있다.
3. @Autowired 의 동작 원리
- BeanPostProcessor : 빈의 인스턴스를 만든다음 빈의 초기화 라이프사이클 이전 또는 이후(@PostConstruct)에 또 다른 작업을 할 수있는 라이프 사이클 콜백
- AutowiredAnnotationBeanPostProcessor : 하나의 빈으로써 스프링 컨테이너에 등록되어 있다. 빈의 초기화 라이프 사이클 이전에 @Autowired를 처리한다.