1. 개요
스프링의 마법같은 @Autowired 어노테이션에 대해 공부하고 정리한 글입니다. @Autowired는 인스턴스를 생성하지 않아도 스프링이 자동으로 인스턴스를 주입해주는 기능입니다.
1.1 의존성이란
2. 의존성 주입 방법 3가지
2.1 @Autowired 사용
아래 코드처럼 빈으로 등록된 객체를 주입하고 싶을 때 @Autowired를 붙인다.
public class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
}
2.2 생성자
@Autowired를 사용하지 않고 생성자를 통해서도 의존성 주입을 할 수 있다.
As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with. However, if several constructors are available, at least one must be annotated with @Autowired in order to instruct the container which one to use.
공식문서에서는 생성자가 하나일 경우 @Autowired는 필수는 아니지만 2개 이상일 경우 붙여줘야 한다.
public class UserRepositoryTest {
private UserRepository userRepository;
@Autowired
public UserRepositoryTest(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
2.3 setter
setter를 이용해서 의존성 주입을 할 수있다.
public class UserRepositoryTest {
private UserRepository userRepository;
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
3. 같은 타입 빈이 여러개일 때
만약 같은 타입의 빈이 여러개일 때 스프링은 어떻게 의존성을 주입해줄까? 아래처럼 Repository를 상속받는 Repository가 2개라고 생각해보자. BookService에서 주입해야 하는 상황
@Repository
public class HyunjunRepository implements BookRepository {
}
@Repository
public class MyBookRepository implements BookRepository {
}
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
}
위 상태에서 주입하려고 하면 '빈이 2개라서 어떤 빈을 주입할 지 모르겠다'는 에러가 뜬다. 그리고 친절하게 해결책을 알려준다.
Description:
Field bookRepository in com.spring.springcore.BookService required a single bean, but 2 were found:
Action :
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
3.1 @primary
@Primary를 사용하면 스프링에서 우선적으로 의존성 주입을 해준다.
@Repository @Primary
public class HyunjunRepository implements BookRepository {
}
3.1.1 ApplicationRunner로 의존성 확인
그럼 실제로 @Primary 빈이 주입됐는지 ApplicationRunner로 살펴보자. ApplicationRunner는 앱이 구동된 다음 실행된다.
@Component
public class BookServiceRunner implements ApplicationRunner {
@Autowired
BookService bookService;
@Override
public void run(ApplicationArguments args) {
bookService.printBookRepository();
}
}
콘솔에서 살펴보면 아래처럼 @Primary가 동작하는 걸 확인할 수 있다.
class com.spring.springcore.HyunjunRepository
3.2 @Qualified
@Qualified는 의존성 주입이 필요한 BookService에 붙인다. 주의할 점은 주입되는 빈의 앞글자는 소문자이다. @Primary가 더 타입에 safe하기 때문에 이 방법은 추천되지 않는다.
@Service
public class BookService {
@Autowired @Qualifier("hyunjunRepository")
private BookRepository bookRepository;
public void printBookRepository() {
System.out.println(bookRepository.getClass());
}
}
3.3 전부 주입
해당하는 타입의 빈을 모두 주입하는 방법이다. 주입이 필요한 BookService에서 필드 타입을 List<>로 선언한다.
@Service
public class BookService {
@Autowired
private List<BookRepository> bookRepositories;
public void printBookRepository() {
this.bookRepositories.forEach(System.out::println);
}
}
3.4 타입이 아닌 필드명으로 주입
사실 스프링은 의존성 주입할 때 타입뿐만 아니라 빈의 이름도 비교한다. 그래서 필드명을 맞춰주면 의존성 주입을 받을 수 있다. 아래 코드를 보면 직접 myBookRepository라는 빈의 이름을 적어주니 스프링이 의존성 주입을 해준다. 다만, 앞글자는 소문자로
@Service
public class BookService {
@Autowired
private BookRepository myBookRepository;
public void printBookRepository() {
System.out.println(myBookRepository.getClass());
}
}
4. AutowiredAnnotationBeanPostProcessor
그럼 어떻게 스프링 내부에 @Autowired가 동작할까? 너무 깊게 알 필요는 없지만 AutowiredAnnotationBeanPostProcessor라는 프로세스를 통해서 의존성이 주입된다. 라이프 사이클 콜백의 일종으로 스프링 앱이 초기화될 때 동작하는 프로세스라고 생각하면 될거 같다. 훗날 더 깊게 공부해보자.
'프로그래밍 > Spring' 카테고리의 다른 글
20.04.26) Spring - Environment (0) | 2020.04.26 |
---|---|
20.04.13) Spring - @ComponentScan (0) | 2020.04.13 |