Programming/Spring framework

스프링 의존 자동 주입 @Autowired와 @Qualifier, 2021-05-31

최동훈1 2021. 6. 1. 01:52

이전 포스트에서 설정클래스의 의존이 필요한 필드에 @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시간 ㅠㅠ...