이전 포스트에서 설정클래스의 의존이 필요한 필드에 @Autowired 애너테이션을 붙이면 스프링에서 @Autowired 가 붙여진 클래스와 타입이 같은 빈 객체를 찾아서 필드에 할당한다.
오늘 공부한 부분은 이 @Autowired를 위치시킬수 있는 곳이다.
1. 필드
우선 가장 기본적인 형태로 의존이 필요한 클래스에서 의존의 대상이 되는 클래스의 참조변수에다가(인스턴스변수) @Autowired를 붙이는 것이다.
public class ChangePasswordService {
@Autowired
private MemberDao memberDao;
public void changePassword(String email, String oldPwd, String newPwd) {
Member member = memberDao.selectByEmail(email);
if (member == null)
throw new MemberNotFoundException();
member.changePassword(oldPwd, newPwd);
memberDao.update(member);
}
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
이렇게 된다면 스프링은 MemberDao "타입" 과 같은 타입의 빈 객체를 찾아서 의존주입 해준다. 또한 @Configuration 빈설정 클래스에서 setMemberDao(MemberDao memberDao)를 구현해 주지 않아도 된다 (세터방식 불필요). 왜냐하면 해주지 않아도, 스프링에서 알아서 의존 주입 해주기 때문이다.
- 필드에 @Autowired를 붙이기 전, 설정클래스에서 ChangePasswordService를 등록할 때, @Configuration에 구현된 ChangePasswordService.
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
-필드에 의존하고자 하는 참조변수에 @Autowired를 붙여서 더이상 의존주입이 필요없게 된 후.
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
//pwdSvc.setMemberDao(memberDao()); 필요없음, 의존을 주입하지 않아도
//스프링이 @Autowired가 붙은 참조변수에 해당타입의 빈객체를 주입
return pwdSvc;
}
2.메서드
-메서드의 파라미터와 같은 타입의 빈 객체를 자동으로 주입한다. 아래 코드의 setMemberDao()메서드에 @Autowired를 붙이니, 파라미터인 MemberDao 타입과 같은 빈 객체를 자동 주입한다.
그래서 위 사례랑 마찬가지로 @Configuration단계에서 굳이 세터 메서드로 의존주입 해줄 필요 없다.
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 setMemberDao(MemberDao memberDao) {
this.memDao = memberDao;
}
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
@Autowired 붙인 경우와 안 붙인 경우를 비교해보길 바란다.
의존 자동주입하기 전에는 setMemberDao메서드를 꼭 써야했다. 의존 자동 주입 이 되니, memberDao는 해당 클래스의 필드로 자동으로 주입된다. 그러므로, 굳이 @Configuration에서 의존주입 해줄 필요 없다.
*단 주입하려는 대상 즉, @Autowired가 붙은 타입의 클래스의 객체는 반드시 빈 객체에 등록되어 있어야 함. 만약 등록되지 않으면,
[일치하는 빈이 없는 경우]: 에러가 남.
@Autowired
public void setMemberDao(DaoDao memberDao) {
this.memDao = memberDao;
}
이 경우 DaoDao 이런 타입이 애초에 빈 객체에 등록되어 있지 않음.
->No qualifying bean of type'DaoDao' available.
*또한 만약 타입이 일치하는 빈이 2가지 이상이면 또 에러가 남
@Bean
public MemberDao memberdao1(){
return MemberDao;
}
@Bean
public MemberDao memberdao2(){
return MemberDao;
}
@Configuration 클래스에 이렇게 MemberDao 타입의 빈 객체 서로 다른 개 2개 등록 되어 있으면,
만약 @Autowired로 MemberDao 필드를 자동의존주입 설정하면, 두개의 빈을 발견했다는 에러가 뜸
-> 이유 빈 객체의 식별자는 "메서드 이름"임 위 예시에서는 memberdao1,memberdao2.
- 이걸 방지하기 위해 @Qualifier 애너테이션이 존재한다. 이 애너테이션은 빈 객체마다 고유한 한정자를 지정하여, @Autowired시 단순히 '타입'으로만 판단하는게 아니라 @Qualifer를 붙임으로서, 정확한 한정자가 매치되어야만, 자동의존 주입이 된다. 한정자 등록이 안된 빈 객체는 메서드의 이름을 디폴트 한정자값으로 가진다.
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService();
}
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummaryPrinter memberPrinter2() {
return new MemberSummaryPrinter();
}
ChangePasswordService의 한정자는(만약, 자동의존주입을 할때, 중복된 타입을 피하기 위해서 @Qualifier을 쓴다면)
'ChangePasswordService' 이다. 나머지 두 빈 객체의 한정자는 각각 "printer","summaryPrinter".
실제 자동 의존 주입시 사용 예.
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
d이런식으로 실제 클래스를 작성할때, 의존 관계가 있는 클래스를 자동 DI 할때, 한정자를 지정해줌으로써, 더욱더 구체적인 빈 객체를 스프링이 찾아서 등록하게끔 한다.
따라서, @Autowired가 붙을수 있는 곳(필드, 메서드) 에는 @Qualifier도 붙을 수 있다.
page 118. 공부완료.
순공부/실습 시간 1시간.
순공부: 책상에 앉아있는 시간이 아닌 내 모든 감각이 책과 코드에 몰입하는 무아지경의 순간.
실제 앉아서 공부한 시간은 3시간 ㅠㅠ...