티스토리 뷰
맴버 필드에 @Autowired
public class MemberRegisterService
{
@Autowired
private MemberDao memberDao;
이렇게 클래스의 맴버 필드에 @Autowired 애노테이션을 붙여주면 해당 객체가 스프링에 의해 자동 주입된다.
스프링 컨테이너의 설정 클래스가 아래와 같다고 해보자
@Configuration
public class AppCtx
{
@Bean
public MemberDao memberDao()
{
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc()
{
return new MemberRegisterService();
}
스프링은 설정 파일을 읽다가 MemberRegisterService 객체를 등록해야 한다는 것을 알게되고 MemberRegisterService 클래스를 찾아갔더니 MemberDao 객체가 @Autowired 표시되어 있으므로 등록된 MemberDao 빈 객체를 찾아 주입한다.
메소드에 @Autowired
public class MemberInfoPrinter
{
private MemberDao memberDao;
private MemberPrinter printer;
@Autowired
public void setMemberDao(MemberDao memberDao)
{
this.memberDao = memberDao;
}
@Autowired
public void setPrinter(MemberPrinter printer)
{
this.printer = printer;
}
}
메소드에 @Autowired를 붙였을때도 마찬가지로, 스프링 설정 파일을 읽다가 MemberInfoPrinter 객체를 등록해야 한다는 것을 알게되고, 해당 클래스로 가보니 두개의 세터 메소드가 @Autowired 되어 있으므로 호출해서 해당 객체를 주입한다.
자동 주입 실패
@Autowired 애노테이션을 적용한 대상에 일치하는 빈 객체가 없으면 익셉션이 발생한다.
또한 @Autowired 애노테이션을 적용한 대상에 일치하는 빈 객체가 2개 이상이어도 자동 주입하려는 빈이 어떤 빈인지 정확히 알 수 없어 익셉션이 발생한다.
@Qualifer 애노테이션을 이용한 의존 객체 선택
@Autowired 애노테이션을 적용한 대상에 일치하는 빈 객체가 2개 이상이라면, 자동 주입하려는 빈이 어떤 빈인지 정확히 알 수 없어 익셉션이 발생한다고 하였다.
따라서 자동 주입할 빈을 정확히 정해줄수 있는 방법이 필요한데, @Qualifer 애노테이션을 이용한다.
우선 @Qualifer 애노테이션을 빈 설정 클래스의 @Bean 애노테이션에 사용한다.
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2()
{
return new MemberPrinter();
}
그리고 클래스에서 @Autowired 애노테이션을 붙여 자동주입 하도록 한 메소드에 붙인다.
@Autowired
@Qualifier("printer")
public void setMemberPrinter(MemberPrinter printer)
{
this.printer = printer;
}
이렇게 하면 @Autowired 에 의해 setMemberPrinter 메소드가 실행되면 같은 한정자 "printer"를 갖는 빈 객체인 memberPrinter1 의 빈 객체가 자동 주입 대상으로 사용된다.
빈의 한정자
기본적으로 스프링은 빈의 이름을 한정자로 지정한다.
@Bean
public MemberPrinter memberPrinter2()
{
return new MemberPrinter();
}
위의 memberPrinter2 빈의 한정자는 memberPrinter2 이다.
하지만 @Qualifer 애노테이션이 있다면 @Qualifer로 지정한 이름이 한정자가 된다.
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
위의 빈의 한정자는 printer 이다.
상속관계와 자동 주입
스프링 컨테이너가 특정 타입 빈을 자동주입해야 하는 @Autowired 애노테이션을 만났을때, 자동 주입해야 하는 타입의 빈이 하나 있고, 해당 타입을 상속받는 또 다른 타입이 있다면 스프링은 어느 빈을 주입해야 할지 알 수 없다.
@Bean
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
@Bean
public MemberSummaryPrinter memberPrinter2()
{
return new MemberSummaryPrinter();
}
예를들어 위와 같이 두 개의 빈이 있고, MemberSummaryPrinter가 MemberPrinter를 상속받는 관계라고 해보자.
스프링 컨테이너가 MemberPrinter를 자동 주입해야 하는 상황이 왔을때 두 가지 타입을 보게 된다.
1. MemberPrinter 타입의 빈인 memberPrinter1
2. MemberPrinter 를 상속 받는 MemberSummaryPrinter 타입의 memberPrinter2
따라서 스프링은 둘 중 어떤 빈을 주입해야할지 알 수 없게 된다.
해결 방법은 두가지가 있다.
1. @Qualifer 애노테이션으로 어떤 빈을 주입할지 정해준다.
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer)
{
this.printer = printer;
}
이렇게 해주면 스프링이 자동주입할때 printer 한정자를 갖는 빈을 주입할것이다.
2. @Autowired 애노테이션이 있는 세터 메소드가 자식 메소드를 사용해야 한다면 정확히 자식 메소드를 인자로 받도록 해준다.
@Autowired
public void setMemberPrinter(MemberSummaryPrinter printer)
{
this.printer = printer;
}
여기서는 인자의 타입이 MemberSummaryPrinter이므로 해당 타입의 인자를 받을 것이다.
자동주입이 필수가 아닐 경우 (@Autowired(required=false), @Nullable)
public class MemberPrinter
{
private DateTimeFormatter dateTimeFormatter;
public void print(Member member)
{
// DateTimeFormatter 객체가 없어도 printer 메소드는 정상작동한다
if(dateTimeFormatter == null)
{
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n",
member.getId(), member.getEmail(), member.getName(), member.getRegisterDateTime());
}
else
{
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n",
member.getId(), member.getEmail(), member.getName(),
dateTimeFormatter.format(member.getRegisterDateTime()));
}
}
// @Autowired 는 자동주입에 필요한 빈 객체가 없으면 익셉션을 발생시킴
@Autowired
public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter)
{
this.dateTimeFormatter = dateTimeFormatter;
}
}
위 클래스의 print() 함수는 DateTimeFormatter 객체가 없어도 if else 문에 의해 정상적으로 작동된다.
즉 해당 함수를 실행하는데 DateTimeFormatter 객체가 필수는 아니라는 것이다.
하지만 아래 세터 메소드에 @Autowired 애노테이션이 있으므로 스프링 컨테이너는 DateTimeFormatter 빈 객체가 등록되있지 않으면 익셉션을 발생 시킨다.
이렇게 자동 주입이 필수가 아닐때 즉, 등록된 빈이 없는 경우 자동 주입을 수행하지 않아도 될 경우 @Autowired 애노테이션에 required 속성을 false로 바꿔준다.
@Autowired(required = false)
public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter)
{
this.dateTimeFormatter = dateTimeFormatter;
}
이제 스프링은 DateTimeFormatter 객체가 빈에 등록되어 있지 않으면 자동주입하지 않고 지나갈 것이다.
(setDateTimeFormatter 메소드를 실행시키지 않음)
또 다른 방법은 주입하는 대상 파라미터 앞에 @Nullable 애노테이션을 붙여도 된다.
@Autowired
public void setDateTimeFormatter(@Nullable DateTimeFormatter dateTimeFormatter)
{
this.dateTimeFormatter = dateTimeFormatter;
}
@Nullable 이 붙은 객체가 빈에 존재하면 해당 빈을 인자로 전달하고, 존재하지 않으면 NULL을 전달한다.
@Autowired(required=false)와 차이점은 setDateTimeFormatter 메소드가 호출된다.
이 방법들은 필드에 @Autowired 애노테이션을 적용했을때도 똑같이 적용된다.
자동 주입과 명시적 의존 주입의 충돌
어떤 빈 객체가 자동 주입과 명시적 의존 주입이 같이 이뤄진다면 자동 주입이 우선시 된다.
다음 설정 클래스를 보자.
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2()
{
return new MemberSummaryPrinter();
}
@Bean
public MemberInfoPrinter infoPrinter()
{
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
infoPrinter.setPrinter(memberPrinter2());
return infoPrinter;
}
MemberInfoPrinter infoPrinter에 세터를 이용해 명시적으로 memberPrinter2 빈을 주입하고 있다.
그런데 세터가 다음과 같이 자동 주입이 이뤄지도록 되어 있다.
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer)
{
this.printer = printer;
}
printer 한정자를 갖는 MemberPrinter 형 빈을 자동 주입하도록 되어 있다.
이렇게 자동 주입과 명시적 주입이 충돌할때는 자동 주입을 통해 일치하는 빈이 주입된다.
즉 위의 경우에는 memberPrinter2 빈이 아닌, 한정자를 printer로 갖는 memberPrinter1 빈이 주입된다.
이런 충돌을 막기위해 @Autowired 애노테이션을 사용했다면 설정 클래스에서 객체를 명시적으로 주입하기 보다는 스프링이 제공하는 자동 주입 기능을 사용하는것이 좋다.
출처 : 스프링5 프로그래밍 입문 (최범균 저)
'Web' 카테고리의 다른 글
| Ch06. 빈 라이프 사이클, 싱글톤이 아닌 빈 객체 (0) | 2022.06.25 |
|---|---|
| Ch05. 컴포넌트 스캔 (0) | 2022.06.24 |
| Ch03. 두 개 이상의 설정파일 사용, @AutoWired, @Import (0) | 2022.06.23 |
| Ch03. DI 방식, Singleton (0) | 2022.06.23 |
| Ch03. Spring Container, ApplicationContext 설정 파일 (0) | 2022.06.01 |
- Total
- Today
- Yesterday
- back tracking
- two pointer
- Python
- 자료구조
- 재귀
- Spring
- priority queue
- recursion
- permutation
- Implementation
- Dijkstra
- BFS
- Stack
- Unity
- DP
- greedy
- CSS
- Brute Force
- graph
- floyd warshall
- binary search
- MVC
- db
- C++
- dfs
- 이분탐색
- C
- Tree
- Kruskal
- 조합
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
