본문 바로가기
Spring/Spring Core

[Section 1] IoC 컨테이너 3부: @Autowired

by kevinntech 2020. 9. 3.

해당 게시물은 백기선님의 스프링 프레임워크 핵심 기술 강좌를 정리한 내용 입니다.

 

1. @Autowired

 

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

 

 

2. @Autowired의 required

 

- @Autowired의 required는 true가 기본 값이다.

 

   필요한 의존 객체의 타입에 해당하는 빈을 찾지 못하면 애플리케이션 구동에 실패한다.

@Service
public class BookService {

    BookRepository bookRepository;

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


- BookRepository가 빈으로 등록되어 있지 않다고 가정 할 때,

 

   아래 코드에서 required를 false로 지정 하면, 의존성 주입을 할 수 없더라도 애플리케이션을 구동한다.

 

   즉, BookRepository가 의존성 주입이 되지 않은 상태로 BookService가 빈으로 등록된다.

@Service
public class BookService {

    BookRepository bookRepository;

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


- 해당 내용은 필드에도 적용 가능 하다.

 

@Service
public class BookService {

    @Autowired(required = false)
    BookRepository bookRepository;
}

 

3. @Autowired를 사용 할 수 있는 위치

 

- @Autowired는 생성자, 세터(setter), 필드(field)에 사용 할 수 있다.

 

   ① 생성자

 

@Service
public class BookService {

    BookRepository bookRepository;

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

 

   ② 세터(setter)

 

@Service
public class BookService {

  BookRepository bookRepository;

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

}

 

   ③ 필드(field)

 

@Service
public class BookService {

    @Autowired
    BookRepository bookRepository;
}

 

4. 같은 타입의 빈이 여러 개 일 때, 의존성 주입

 

      아래의 BookRepository 인터페이스를 구현한 클래스(MyBookRepository, KeesunBookRepository)가 2개 있다.

 

public interface BookRepository { }

 

@Repository
public class MyBookRepository implements BookRepository { }

 

@Repository
public class KeesunBookRepository implements BookRepository{ }

 

      BookService 클래스에서는 @Autowired로 BookRepository를 주입 받으려고 하는데 에러가 발생한다. 

 

      에러가 발생한 이유는 두 개의 클래스 중 어떤 클래스를 주입해야 하는지 알 수 없기 때문이다.

 

@Service 
public class BookService { 
   @Autowired 
   BookRepository bookRepository; 
}

 

      해결책으로는 다음 3가지가 존재한다.

 

      @Primary : 같은 타입의 빈이 여러 개 일 때, 우선 순위를 가지는 빈으로 지정하여 해당 빈이 주입 되도록 한다.

 

@Repository
@Primary
public class KeesunBookRepository implements BookRepository{}


      @Qualifier : @Autowired와 함께 사용하며 빈의 이름이 같은 객체를 찾는다. 
                                     * 빈의 이름 : @Service 또는 @Repository 등이 붙은 클래스 명에서 첫 글자만 소문자로 변경한 것이다.

                                    @Qualifier 보다 좀 더 type-safe 한 @Primary를 사용하는 것을 권장한다. 
     

@Autowired
@Qualifier("keesunBookRepository")
BookRepository bookRepository;

 

      해당 타입의 모든 빈을 주입 받기

            다음과 같이 List를 사용하면 해당 타입의 (BookRepository) 타입의 모든 빈을 주입 받을 수 있다.

 

@Autowired
List<BookRepository> bookRepository;

 

            어떠한 빈이 주입 되었는지 확인 하기 위해 다음과 같이 Runner를 만든다. 

            (Runner에 대한 자세한 내용은 스프링 부트 강좌를 참고)

 

@Component
public class BookServiceRunner implements ApplicationRunner {

    @Autowired
    BookService bookService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        bookService.printBookRepository();
    }
}


            BookService에 어떤 BookRepository 빈이 주입 되었는지 출력하는 메서드를 정의한 다음, BookServiceRunner에서

            해당 메서드를 호출한다.

@Service
public class BookService {

    @Autowired
    BookRepository bookRepository;

    // BookService에 어떤 BookRepositor빈이 주입 되었는지 출력하는 메서드 정의
    public void printBookRepository(){
        System.out.println(bookRepository.getClass());
    }
}

 

5. @Autowired 동작 원리

 

BeanPostProcessor의 구현체인 AutowiredAnnotationBeanPostProcessor가 Bean의 초기화 라이프 사이클 이전에

@Autowired 애노테이션이 붙어 있는 빈(Bean)을 찾아 주입 한다.

 

 

댓글