그런데 의문점이 생길 것이다. 만약 @Autowired를 사용해서 의존 자동주입의 대상이 되는 빈을 컨테이너에서 찾을때, 컨테이너에 등록되어 있는 해당 타입과 일치하는 빈이 여러개이면 어떤 일이 일어날까?
우선 테스트를 해보자.
@Configuration
@Import(AppCtx2.class)
public class AppCtx1 {
@Bean
public MemberDao memberdao() {
MemberDao m=new MemberDao();
return m;
}
@Bean
public MemberDao memberdao2() {
MemberDao m=new MemberDao();
return m;
}
@Bean
public MemberRegisterService mrsvc() {
MemberRegisterService mrsvc=new MemberRegisterService();
return mrsvc;
}
@Bean
public PasswordChangeService pcsvc() {
PasswordChangeService pcsvc=new PasswordChangeService(memberdao());
return pcsvc;
}
}
이렇게 스프링 설정 클래스에 @Autowired로 주입해줄 MemberDao 타입의 빈을 하나 추가 해 줬다.
여기서 내가 또 이해되지 않은 것이 있는데, 그럼 분명 싱글톤이라 했는데 같은 빈 객체가 2개 생기는 것인가..? 라는 의문점이 생겼지만, 스프링 컨테이너에 등록되는 빈 식별자는 설정 메서드의 "이름" 인 memberdao() 와 memberdao2() 이기 때문에 같은 빈 객체가 아닌 각각의 다른 빈 객체라는 것을 이해하였다.
실행을 해 보면,
No qualifying bean of type 'chap04.MemberDao' available: expected single matching bean but found 2: memberdao,memberdao2
이런 오류가 나온다. 즉, 1개의 타입 빈이 일치해야 하는데, 의존주입을 할려고, 스프링 컨테이너에 @Autowired가 붙은 빈의 타입을 찾아보니, 2개가 나왔다는 뜻이다.
이런 문제를 해결하기 위해서는, 스프링 컨테이너에 입력할 빈의 "식별자"를 자동주입 전용으로 "재정의 할 필요가 있다." 즉, 일반적인 스프링 빈으로써의 식별자는 메서드의 이름인 "memberdao() 와 memberdao2()" 이지만, @Autowired 애너테이션을 통한 자동주입 한정으로, 또 다른 식별자를 붙이는 것이다.
이떄, 사용되는 애너테이션이 @Qualifier 애너테이션이다. 이 애너테이션을 사용해서 앞서 정의한 같은 타입의 MemberDao 객체를 한정해 보겠다.
@Configuration
@Import(AppCtx2.class)
public class AppCtx1 {
@Bean
@Qualifier("dao1")
// 같은 타입의 빈 객체를 구별하기위한 한정자를 지정함.
public MemberDao memberdao() {
MemberDao m=new MemberDao();
return m;
}
@Bean
@Qualifier
//이렇게 한정자로 별도의 이름을 지정하지 않았을 경우에는,
빈 객체의 식별자가 한정자로 됨.
public MemberDao memberdao2() {
MemberDao m=new MemberDao();
return m;
}
@Bean
public MemberRegisterService mrsvc() {
MemberRegisterService mrsvc=new MemberRegisterService();
return mrsvc;
}
@Bean
public PasswordChangeService pcsvc() {
PasswordChangeService pcsvc=new PasswordChangeService(memberdao());
return pcsvc;
}
}
또 @Qualifier를 이용해서는 한정자를 명시적으로 지정하는 경우와 그렇지 않은 경우가 있는데 위의 내가 작성한 사례처럼, 별도로 지정하지 않고, @Qualifier만 붙인다면 "빈 객체의 식별자인 메서드 이름"이 그대로 "한정자"가 된다.
public class MemberRegisterService {
@Autowired
@Qualifier("dao1")
//자동 의존 주입할 빈의 한정자를 지정하였다.
private MemberDao memberdao;
public MemberRegisterService(MemberDao memberdao) {
this.memberdao = memberdao;
}
public MemberRegisterService() {
// TODO Auto-generated constructor stub
}
public void registermember(Member m) {
Member m1=memberdao.getidentifier(m);
if(m1!=null) {
throw new DuplicateMemberException("등록된 멤버의 ID가 중복되어있습니다.");
}
else {
memberdao.register(m);
System.out.println("등록완료 ID: "+m.getId()+" pwd: "+m.getPwd() );
}
}
}
이렇게 실제 클래스에 의존 자동주입을 위한 애너테이션 밑에 한정자를 작성하니, 정상적으로 작동이 되었다.
또 주의해야 할 점은 만약 상속관계에 있는 조상타입의 빈을 자동주입 할 때도, 만약에 스프링 컨테이너에 자동주입할 빈을 상속한 자손타입의 빈이 있다면 동일한 익셉션이 난다. 이유는 다형성 때문이다. 이건 당연한 문제이기에 별도의 예시는 안들겠다.
'기록 > Spring framework' 카테고리의 다른 글
@Component, 컴포넌트 스캔( 자동 스프링 빈 등록). 2021-11-23 (0) | 2021.11.23 |
---|---|
@Autowired의 스프링 빈 필수여부( null 값 전달.), 의존 자동주입과 수동주입의 우선순위. 2021-11-18 (2) | 2021.11.18 |
자동 의존 주입 @Autowired 의 실질적 적용 (세터 메서드, 필드). 2021-11-11 (0) | 2021.11.11 |
스프링 설정 클래스에서 @Autowired를 통한 자동 DI, 설정메서드(세터) 형식의 DI, 두개 이상의 설정 클래스로 스프링 컨테이너 만들기. 2021-10-22 (0) | 2021.10.22 |
스프링의 역할: 객체 조립기(@Configuration) (0) | 2021.10.19 |