2021. 7. 12. 14:15ㆍJAVA/Spring
4. 상위/하위 타입 관게와 자동 주입
목적
본 글의 목적은 상위 클래스와 하위 클래스를 정의하고 해당 타입의 빈 설정 메소드를 같은 스프링 설정 클래스 안에서 정의한다. 그리고 스프링이 자동 의존 주입 대상 선택시 예외가 발생하는지 확인한다.
우선 상위/하위 클래스를 정의하기 위해 MemberPrinter 클래스와 MemberSummary 클래스를 정의한다.
MemberPrinter 클래스 정의
public class MemberPrinter {
public void print(Member member)
{
System.out.printf("회원 정보 : 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n",
member.getId(), member.getEmail(), member.getName(), member.getRegisterDateTime());
}
}
MemberSummaryPrinter 클래스 정의
public class MemberSummaryPrinter extends MemberPrinter{
@Override
public void print(Member member) {
System.out.printf("회원정보 : 이메일=%s, 이름=%s\n",member.getEmail(), member.getName());
}
}
MemberSummaryPrinter 클래스는 MemberPrinter 클래스의 하위 클래스임을 확인할 수 있다.
스프링 설정 클래스(AppCtx 클래스) 정의
@Configuration
public class AppCtx{
... 생략
// 특이점
// memberPrinter1 빈 설정 메소드와 memberPrinter2 빈 설정 메서드가
// 리턴의 이름은 다르지만 MemberSummaryPrinter는 MemberPrinter 클래스의
// 하위 클래스 이므로 자동 의존 주입 과정에서 중복을 일으키는 문제가 발생한다.
@Bean
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
@Bean
public MemberSummaryPrinter memberPrinter2()
{
return new MemberSummaryPrinter();
}
}
MemberInfoPrinter 클래스 정의
public class MemberInfoPrinter {
private MemberDao memDao;
private MemberPrinter printer;
public void printMemberInfo(String email)
{
Member member = memDao.selectByEmail(email);
if(member==null)
{
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
// 특이점
// @Qualifier 애노테이션 삭제
@Autowired
public void setMemDao(MemberDao memDao) {
this.memDao = memDao;
}
@Autowired
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
MemberListPrinter 클래스 정의
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import chap04_04.spring.Member;
import chap04_04.spring.MemberDao;
import chap04_04.spring.MemberPrinter;
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
public MemberListPrinter()
{
}
public MemberListPrinter(MemberDao memberDao, MemberPrinter printer)
{
this.memberDao = memberDao;
this.printer = printer;
}
public void printAll()
{
Collection<Member> members = memberDao.selectAll();
members.forEach(m->printer.print(m));
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
// 특이점
// @Qualifier 애노테이션 삭제
@Autowired
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
MainForSpring 클래스 정의
yonghwankim-dev/spring5
최범균 저, 초보 웹 개발자를 위한 스프링5 프로그래밍 입문 예제. Contribute to yonghwankim-dev/spring5 development by creating an account on GitHub.
github.com
실행결과
결과분석
상위 클래스와 하위 클래스로 정의했더라도 스프링 컨테이너는 @Qualifier 애노테이션 없이 빈 설정 메서드를 한정지을 수 없다.
상위 클래스, 하위 클래스 이름으로 따로 빈 설정 메소드로 정의했음에도 불구하고 예외가 발생하는 이유는 MemberSummaryPrinter 클래스가 MemberPrinter 클래스를 상속했기 때문이다. MemberSummaryPrinter 클래스는 MemberPrinter 타입에도 할당 할 수 있으므로, 스프링 컨테이너는 MemberPrinter 타입 빈을 자동 주입해야 하는 @Autowired 애노테이션 태그를 만나면 memberPrinter1 빈과 memberPrinter2 타입 빈 중에서 어떤 빈을 주입해야 할지 알 수 없다. 그래서 예외를 발생시키는 것이다.
상위/하위 타입 관계에서 @Qualifier 애노테이션을 통한 자동 주입 수행
MemberListPrinter 클래스와 MemberInfoPrinter 클래스가 MemberPrinter 타입의 빈을 자동 주입하므로 어떤 빈을 주입할지 결정해야 한다.
스프링 설정 클래스에 @Qualifier 애노테이션 적용 (printer)
@Configuration
public class AppCtx{
... 생략
// 특이점
// @Qualifier 애노테이션 적용, 한정자 값 "printer"로 설정
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1()
{
return new MemberPrinter();
}
// 특이점
// @Qualifier 애노테이션 적용, 한정자 값 "summaryPrinter"로 설정
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2()
{
return new MemberSummaryPrinter();
}
}
MemberInfoPrinter 클래스에 @Qualifier 애노테이션 적용
public class MemberInfoPrinter {
private MemberDao memDao;
private MemberPrinter printer;
public void printMemberInfo(String email)
{
Member member = memDao.selectByEmail(email);
if(member==null)
{
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
@Autowired
public void setMemDao(MemberDao memDao) {
this.memDao = memDao;
}
// 특이점
// @Qualifier 애노테이션 적용, 스프링이 자동 주입시 memberPrinter1() 메소드로 한정하게됨
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
MemberListPrinter 클래스에 @Qualifier 애노테이션 적용 (summaryPrinter)
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
public MemberListPrinter()
{
}
public MemberListPrinter(MemberDao memberDao, MemberPrinter printer)
{
this.memberDao = memberDao;
this.printer = printer;
}
public void printAll()
{
Collection<Member> members = memberDao.selectAll();
members.forEach(m->printer.print(m));
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
// 특이점
// @Qualifier 애노테이션 적용, 스프링이 자동 주입시 memberPrinter2() 메소드로 한정하게됨
@Autowired
@Qualifier("summaryPrinter")
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
MainForSpring 클래스 정의
yonghwankim-dev/spring5
최범균 저, 초보 웹 개발자를 위한 스프링5 프로그래밍 입문 예제. Contribute to yonghwankim-dev/spring5 development by creating an account on GitHub.
github.com
실행결과
결과분석
위 결과를 통해서 info 명령어 수행결과 MemberInfoPrinter 클래스의 자동 주입이 memberPrinter1() 메서드를 통해서 주입된 것을 알 수 있다. 그리고 list 명령어 수행결과 MemberListPrinter 클래스의 자동 주입이 memberPrinter2() 메서드를 통해서 주입된 것을 알 수 있다.
정리하며
상위/하위 클래스 타입의 빈 메소드를 작성하여도 @Qualifier 애노테이션을 따로 지정하지 않으면 스프링은 빈을 한정지을 수 없다. 이유는 하위 클래스는 상위 클래스에 할당이 가능하기 때문이다. 따라서 각각의 빈 메소드에 @Qualifier 애노테이션을 지정하면 상위/하위 클래스를 작성하여도 자동 주입할 빈 메소드를 한정 지을 수 있다.
References
초보 웹 개발자를 위한 스프링5 프로그래밍 입문, 최범균 저
https://github.com/yonghwankim-dev/spring5
'JAVA > Spring' 카테고리의 다른 글
4. 의존 자동 주입 #6 자동 주입과 명시적 의존 주입 간의 관계 (0) | 2021.07.12 |
---|---|
4. 의존 자동 주입 #5 @Autowired 애노테이션의 필수 여부 (0) | 2021.07.12 |
4. 의존 자동 주입 #3-2 @Qualifier 애노테이션 적용을 통한 특정 빈 설정 메소드 수행 확인 (0) | 2021.07.12 |
4. 의존 자동 주입 #3-1 @Qualifier 애노테이션을 이용한 의존 객체 선택 (0) | 2021.07.09 |
4. 의존 자동 주입 #2 @Autowired 애노테이션을 이용한 의존 자동 주입 (0) | 2021.07.09 |