@Target {ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired{
/**
Declares whether the annotated dependency is required.
<p>Defaults to {@code true}.
*/
boolean required() default true;
}
setter 메소드에서도 @Autowired 어노테이션을 부여하여 사용할 수 있습니다. 위의 그림은 실제 @Autowired 어노테이션 인터페이스입니다. @Target을 보면 CONSTRUCTOR, METHOD, PARAMETER, FIELD, ANNOTATION_TYPE 등에 부여가 가능한것이 보입니다. 우리는 여기서 @Autowired 어노테이션 인터페이스가 가지고 있는 required() 메소드에 주목해야 합니다.
위의 예제는 정상적으로 실행되지만 bookRepository Class의 Bean등록 어노테이션을 제거 하면 아래와 같이 오류가 발생합니다.
setter로 주입되는 의존성의 경우에는 생성자 처럼 필수적으로 의존성 주입이 되어야하는 것이 아닙니다.
필요에 의해서 주입이 되는 것입니다.
하지만 @Autowired 어노테이션 인터페이스에서 보았던 required() 때문에 오류가 발생합니다.
Default 값이 True 되어 있었기 때문입니다.
required가 true인 경우에는 해당 의존성은 "꼭 필요한 대상이므로 주입을 반드시 받아야 한다"라는 의미가 되어버립니다.
required를 false로 설정해보면 Bean에 등록 되어있지 않음에도 bookRepository를 Autowired한 것을 볼 수 있습니다.
생성자에서 의존성을 주입받는 경우에는 @Autowired 어노테이션을 생략하더라도 자동으로 의존성을 주입받을 수 있습니다. 생성자의 매개변수로 객체를 전달받도록 되어있는 경우에는 해당 객체가 생성될 때에는 반드시 그 객체를 주입받아야 하기 때문입니다.
@Service
public class BookService{
private BookRepository bookRepository;
public BookService(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
}
위와 같이 생성자에 BookRepository를 주입받는 경우 @Autowired가 없더라도 자동으로 주입을 받게 되어있습니다.
BookRepository의 Bean으로 등록되기 위한 어노테이션을 제거해보면 아래와 같이 오류가 납니다.
BookService Class에 @Autowired 어노테이션이 부여되어 있지 않음에도 Autowired할 수 없다는 문구가 나타납니다.
간단히 BookRepository Interface를 생성하고 그것을 구현한 2개의 클래스(MyBookRepository, SecondBookRepositor)를 생성했습니다.
@Repository
public class MyBookRepository implemyents BookRepository{
}
,
@Repository
public class SecondBookRepository implements BookRepository{
}
BookService Class를 확인해보면 이때에는 위와 같이 "한개 이상의 BookRepository Type이 존재합니다"라는 오류메시지가 나타나며 컴파일에 실패하게 됩니다.
@Autowired에 대상이 되는 클래스들 중 주입이 되길 원하는 클래스에 이 어노테이션을 부여하면 Spring이 자동으로 해당 객체를 주입하게 됩니다.
@Service
public class BookService{
@Autowired
@Qualifier("myBookRepository")
private BookRepository bookRepository;
public void printBookRepository(){
System.out.println(bookRepository.getClass());
}
}
@Autowired 어노테이션으로 주입하는 곳에서 @Qualifier("bean id")를 이용해 어떤 Bean이 주입될지를 명시함으로써 해결할 수도 있습니다.
@Service
public class BookService{
@Autowired
private List<BookRepository> bookRepository;
public void printBookRepository(){
this.bookRepository.forEach(System.out::println);
}
}
마지막으로 모든 타입의 Bean을 주입받도록 할 수 있습니다. @Autowired로 주입받는 객체의 형을 List로 받도록 합니다. 그렇게 되면 해당 타입을 가지는 IoC 컨테이너에 존재하는 모든 Bean이 List안에 들어가게 됩니다.