Chap 04 의존 자동 주입
@Autowired 애노테이션을 이용한 자동주입
- 자동 주입 기능을 사용하면 스프링이 알아서 의존 객체를 찾아서 주입한다.
- 의존 주입 기능은 의존을 주입할 대상에 @Autowired 애노테이션을 붙이면 된다.
package spring;
import org.springframework.beans.factory.annotation.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;
}
}
package spring;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberInfoPrinter {
private MemberDao memberDao;
private MemberPrinter memberPrinter;
public void printMemberInfo(String email) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
System.out.println("������ ����\n");
return;
}
memberPrinter.print(member);
System.out.println();
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
public void setMemberPrinter(MemberPrinter memberPrinter) {
this.memberPrinter = memberPrinter;
}
}
package spring;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberRegisterService {
@Autowired
public MemberDao memberDao;
public Long regist(RegisterRequest req) {
Member member = memberDao.selectByEmail(req.getEmail());
if(member != null) {
throw new DuplicateMemberException("dup email "+ req.getEmail());
}
Member newMember = new Member(req.getEmail(), req.getPassword(), req.getName(), LocalDateTime.now());
memberDao.insert(newMember);
return newMember.getId();
}
}
package spring;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
public void printAll() {
Collection<Member> members = memberDao.selectAll();
System.out.println(members);
members.forEach(m->printer.print(m));
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
package config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberInfoPrinter;
import spring.MemberListPrinter;
import spring.MemberPrinter;
import spring.MemberRegisterService;
import spring.VersionPrinter;
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService();
}
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService();
}
@Bean
public MemberListPrinter listPrinter() {
return new MemberListPrinter();
}
@Bean
public MemberInfoPrinter infoPrinter() {
return new MemberInfoPrinter();
}
@Bean
public VersionPrinter versionPrinter() {
VersionPrinter versionPrinter = new VersionPrinter();
versionPrinter.setMajorVersion(5);
versionPrinter.setMinorVersion(0);
return versionPrinter;
}
}
일치하는 빈이 없는 경우
- @Autowired하지않은 빈을 의존주입하려는 경우 에러가 발생한다. 예를들어 memberDao라는 빈을 만들어놓지 않은 상태에서 주입 받으려고하면 오류가 발생한다.
- @Autowired로 MemberList클래스 타입의 인자를 주입받고 싶은데 빈에 MemberList빈이 2개이상이면 오류가 발생한다 따라서 @Qualifier를 사용하자
@Qualifier 애노테이션을 이용한 의존 객체 주입
- @Qualifier 애노테이션을 이용하면 자동 주입 대상 빈을 한정 할 수 있다.
- 필드와 메서드에 모두 적용할 수 있다.
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2() {
r
package spring;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter memberPrinter;
public void printAll() {
Collection<Member> members = memberDao.selectAll();
System.out.println(members);
members.forEach(m->memberPrinter.print(m));
}
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
@Qualifier("printer")
public void setPrinter(MemberPrinter printer) {
this.memberPrinter = printer;
}
}
빈 이름과 기본 한정자
- 빈 설정에 @Qualifer 애노테이션이 없으면 빈의 이름을 한정자로 지정한다
- 같은 타입의 빈을 주입받는경우 타입일치하는게 2개이상이면 이름이 같은 빈을 주입한다.
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2() {
return new MemberPrinter();
}
상위/하위 타입 관계 자동 주입
- 상속한 클래스는 상위클래스와 같은 빈으로 처리됨
- 따라서 어떤 타입의 빈을 주입해야될지 알수없어서 오류가 발생
package spring;
public class MemberSummarayPrinter extends MemberPrinter{
@Override
public void print(Member member) {
System.out.printf("회원 정보 : 이메일 =%s , 이름 = %d\n",member.getEmail(),member.getName());
}
}
@Bean
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberSummarayPrinter memberPrinter2() {
return new MemberSummarayPrinter();
}
- 이 문제를 해결하기위한 방법
- 두개의 빈의 @Qualifer를 다르게 줌
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter")
public MemberSummarayPrinter memberPrinter2() {
return new MemberSummarayPrinter();
}
- 주입하는 곳에서 타입이 하위클래스가 되도록 설정
@Autowired.
public void setPrinter(MemberSummaryPrinter printer) {
this.memberPrinter = printer;
}