[Spring] @Autowired의 다양한 사용 방법 - required, Primary, Qualifier
[Spring] @Autowired의 다양한 사용 방법 - required, Primary, Qualifier
1. 의존객체 타입의 빈이 없는 경우
다음과 같이 BookService 클래스와 BookRepository 인터페이스가 있다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
BookRepository bookRepository;
@Autowired
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
//
public interface BookRepository {
}
BookService 클래스에는 @Service 애노테이션을 붙여 빈으로 등록해주었고 BookRepository는 애노테이션을 붙이지 않은 일반 자바 클래스이다.
BookRepository는 BookService의 의존객체이며 @Autowired를 붙여 BookService의 생성자를 통해 주입받도록 하였다.
이대로 실행하면 에러가 난다.
BookService 빈을 생성하려면 BookRepository 빈이 필요한데 IoC 컨테이너에서 해당하는 타입의 빈을 찾을 수 없으니 BookRepository를 빈으로 등록하라는 뜻이다.
코드를 바꿔 이번엔 setter로 주입받도록 해보자.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
BookRepository bookRepository;
@Autowired
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
//
public interface BookRepository {
}
실행하면 역시 에러가 발생한다.
생성자로 주입받던 것과 달리 Setter로 주입받도록 했기때문에 원래는 BookService의 인스턴스는 생성할 수 있는게 맞지만 @Autowired 애노테이션에 의해 BookRepository를 주입받도록 설정한 BookService도 생성되지 않는 것이다.
이렇게 @Autowired 애노테이션을 처리하던 중 해당하는 빈의 타입을 못찾거나 의존성 주입을 할 수 없는 경우에는 에러가 발생하며 어플리케이션 구동이 제대로 되지 않는다.
@Autowired에 required 속성값을 추가해보자.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
BookRepository bookRepository;
@Autowired(required = false)
public void setBookRepository(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
}
//
public interface BookRepository {
}
이번엔 에러 없이 정상적으로 실행된다.
@Autowired(required = false)은 의존성을 'Optional'로 설정하는 것이다.
주입받을 의존객체가 필수적이지 않을 경우 @Autowired(required = false)로 설정해서 의존객체를 주입받지 못하더라도 빈을 생성하도록 할 수 있다.
결과적으로 BookService는 BookRepository를 주입받지 않은 상태로 IoC 컨테이너에 등록된다.
required 속성의 기본값은 true이기 때문에 지정하지 않을 경우 setter로 주입받게 했더라도 의존객체를 주입받지 못하면 항상 에러가 발생한다.
required = false는 @Autowired를 필드나 setter에 붙였을 경우에만 사용할 수 있다.
2. 의존객체 타입의 빈이 여러개인 경우
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
BookRepository bookRepository;
}
//
public interface BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class MyBookRepository implements BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class AnotherBookRepository implements BookRepository {
}
BookService에서 BookRepository를 필드로 주입받도록 변경한다.
MyBookRepository, AnotherBookRepository 클래스를 새로 만들고 BookRepository를 구현하도록 한다.
둘 다 @Repository를 붙여 빈으로 등록함으로써 BookRepository 타입의 빈이 두개가 되었다.
이 경우 spring은 BookService에 어떤 BookRepository 빈을 주입해줄까?
결과는 주입해 줄 수 없다.
두 BookRepository중 어떤 빈을 원하는지 spring 입장에서 알 수가 없기 때문이다.
1) @Primary
@Primary 애노테이션을 사용해서 해당하는 타입의 빈이 여러개일 경우 우선적으로 주입할 빈을 지정할 수 있다.
MyBookRepository에 @Primary 애노테이션을 붙이자.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
BookRepository bookRepository;
}
//
public interface BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository @Primary
public class MyBookRepository implements BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class AnotherBookRepository implements BookRepository {
}
이렇게 하면 spring은 BookService에 BookRepository를 주입할때 여러개의 빈이 존재할 경우 @Primary 애노테이션이 붙어있는 빈을 주입해준다.
2) Qualifier
@Qualifier 애노테이션을 사용해서 빈 id를 지정해서 주입받을 수 있다.
다음과 같이 주입받는 곳에 @Qualifier 애노테이션을 추가하자.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired @Qualifier("myBookRepository")
BookRepository bookRepository;
}
//
public interface BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class MyBookRepository implements BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class AnotherBookRepository implements BookRepository {
}
기본적으로 @Repository 애노테이션을 쓰면 빈 id는 소문자로 시작하는 클래스 이름과 동일하다.
따라서 MyBookRepository를 주입받도록 설정하려면 Qualifier 애노테이션에 myBookRepository라고 지정해주면 된다.
이렇게 @Primary와 @Qualifier 애노테이션은 같은 목적으로 쓸 수 있지만 @Primary가 더 type safe한 방법이다.
3) 해당하는 타입의 빈을 모두 주입받기
BookService에서 BookRepository를 주입받는 변수의 타입을 List로 변경한다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
@Autowired
List<BookRepository> bookRepositories;
}
//
public interface BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class MyBookRepository implements BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class AnotherBookRepository implements BookRepository {
}
이렇게 하면 spring은 BookRepository 타입의 빈을 모두 주입해준다.
4) 빈 id와 변수명을 동일하게
별로 spring에서 추천하는 방법은 아니지만 @Autowired는 타입을 보고 나서 여러 개일 경우 변수명과 빈 id도 확인하는 과정을 거친다.
예를 들어 지금처럼 BookRepository 타입의 빈이 MyBookRepository, AnotherBookRepository가 존재하는 상태에서 MyBookRepository를 주입받고 싶으면 주입받을 변수명을 myBookRepository로 하면 된다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class BookService {
@Autowired
BookRepository myBookRepository;
}
//
public interface BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class MyBookRepository implements BookRepository {
}
//
import org.springframework.stereotype.Repository;
@Repository
public class AnotherBookRepository implements BookRepository {
}
여러 개의 빈 중에서 변수명과 빈 id가 동일한 빈이 주입된다.
References
'Spring Framework > Spring Core' 카테고리의 다른 글
[Spring] EnvironmentCapable - Profile 사용하기 (0) | 2021.04.21 |
---|---|
[Spring] 빈의 Scope - 싱글톤과 프로토타입 (0) | 2021.04.21 |
[Spring] Component Scan과 Function을 사용한 빈 등록 방법 (0) | 2021.04.21 |
[Spring] @Autowired 동작 원리 - BeanPostProcessor (0) | 2021.04.21 |
[Spring] 빈을 설정하는 3가지 방법 - XML, JAVA, Component Scan (0) | 2021.04.21 |
[Spring] 왜 자바 객체를 IoC 컨테이너의 빈으로 만들까? (0) | 2021.04.21 |
[Spring] 스프링 PSA (0) | 2021.04.21 |
[Spring] 스프링 AOP 개념 이해 및 적용 방법 (0) | 2021.04.21 |