3.@Autowired

@Autowired

필요한 의존 객체의 “타입”에 해당하는 빈을 찾아 주입한다.

생성자, 세터, 필드에 사용가능하다 아래 예시를 참고하자.

BookService의 생성자에 Autowired를 달았다. 잘동작할것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class BookService {
BookRepository bookRepository;

@Autowired
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
///////////////////////////////////
@Repository
public class BookRepository{

}

이번에는 세터에다 Autowired를 달아주고 @Repository를 지워보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class BookService {
BookRepository bookRepository;

@Autowired
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
///////////////////////////////////

public class BookRepository{

}

위는 실패하는데 왜 실패할까
단순 세터에 Autowired만 붙였으므로 인스턴스 생성은 되어야 하는거아녀?

Autowired가 있기때문에 의존성 주입을 시도하게되고 이로 인해 실패한다.

실패를 벗어나기 위해서는 @Autowired(require = false)로 해결할 수 있다.

즉 생성자가 아닌곳에 붙은 @Autowird는 require = false 옵션을 적절히 활용할 수 있다.
(생성자에 Autowired(required = false) 가 붙어있으면 객체 자체 생성이 불가능하므로 생성자에는 부적절)

해당 타입의 빈이 여러개인 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface A {
..
}

@Repository
class BRepository implements ARepository {
..
}

@Repository
class CRepository implements ARepository {
..
}


@service
public class AService {
@Autowired
ARepository aRepository;
}

AService의 aRepository에는 누가 주입될까?
내가 어떤걸 원하는지 스프링은 모르기 때문에 에러가 발생한다.

해결방법은?

  1. @Primary 어노테이션 붙이기 (추천)

    1
    2
    3
    4
    @Repository @Primary
    class CRepository implements ARepository {
    ..
    }

    위처럼 할경우 CRepository가 주입된다.

  2. Qualifier 활용

    1
    2
    3
    4
    5
    @service
    public class AService {
    @Autowired @Qualifier("cRepository")
    ARepository aRepository;
    }

    위처럼 할경우 CRepository가 주입된다.

  3. 해당 타입의 빈 모두 주입받기

    1
    2
    3
    4
    5
    @service
    public class AService {
    @Autowired
    List<ARepository> aRepository;
    }

    리스트에 BRepository , CRepository가 들어간다.

  4. 추천하진 않지만 알고만 있어라

    1
    2
    3
    4
    5
    @service
    public class AService {
    @Autowired
    ARepository cRepository;
    }

Autowired는 타입만 보는것이 아니라 이름도 한번 보기때문에 위처럼 할 경우 cRepository를 주입받을 수 있다.


동작원리는?

BeanPostProcessor
새로 만든 빈 인스턴스를 수정할 수 있도록 도와주는 인터페이스이다.

AutowiredAnnotationBeanPostProcessor​ extends BeanPostProcessor
위에 보다시피 AutowiredAnnotationBeanPostProcessor​가 BeanPostProcessor을 상속하여 사용하는데 초기화 이전에 @Autowired같은 어노테이션을 찾아 주입을 해준다.

이제 동작원리 설명
ApplicationContext (BeanFactory)가 BeanPostProcessor을 구현한 빈을 찾고 AutowiredAnnotationBeanPostProcessor를 찾아 일반적인 빈들에게 해당 로직을 적용하는것이다.
(결국 AutowiredAnnotationBeanPostProcessor​도 빈으로 등록되어있다는것)
(ApplicationContext는 빈 들을 갖고있다)

Share