4. 의존 자동 주입 #2 @Autowired 애노테이션을 이용한 의존 자동 주입

2021. 7. 9. 11:52JAVA/Spring

본 글은 최범균 저자의 초보 웹 개발자를 위한 스프링5 프로그래밍 입문 도서의 내용을 복습하기 위해 작성한 글입니다.

2. @Autowired 애노테이션을 이용한 의존 자동 주입

자동 주입 기능을 사용하면 스프링이 알아서 의존 객체를 찾아서 주입한다.

Before

@Bean
public MemberDao memberDao() 
{
	return new MemberDao();
}

@Bean
public ChangePasswordService changePwdSvc()
{
	ChangePasswordService pwdSvc = new ChangePasswordService();
	pwdSvc.setMemberDao(memberDao());
	return pwdSvc;
}

자동 주입 기능을 사용하면 @Bean 메서드에서 의존을 주입하지 않아도 의존 객체가 아래와 같이 주입된다.

After

@Bean
public MemberDao memberDao() 
{
	return new MemberDao();
}

@Bean
public ChangePasswordService changePwdSvc()
{
	ChangePasswordService pwdSvc = new ChangePasswordService();
	return pwdSvc;
}

 

자동 의존 주입 기능 사용 방법

  • 의존을 주입할 의존 객체 위에 @Autowired 애노테이션을 붙인다.

ChangePasswordService.java

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;
	}
}

필드에 @Autowired 애노테이션이 붙어있으면 스프링이 해당 타입의 빈 객체를 찾아서 필드에 할당한다.

AppCtx.java

@Configuration
public class AppCtx{
	
	@Bean
	public MemberDao memberDao() 
	{
		return new MemberDao();
	}
	
	@Bean
	public MemberRegisterService memberRegSvc()
	{
		return new MemberRegisterService(memberDao());
	}
	
	@Bean
	public ChangePasswordService changePwdSvc()
	{
		ChangePasswordService pwdSvc = new ChangePasswordService();
		// 의존을 주입하지 않아도 스프링이 @Autowired가 붙인 필드에
		// 해당 타입의 빈 객체를 찾아서 주입한다.
		return pwdSvc;
	}
    .. 생략

ChangePasswordService 클래스의 memberDao 필드에 @Autowired 애노테이션을 붙였으므로 스프링 설정 클래스인 AppCtx 클래스는 ChangePasswordService 객체를 생성시 따로 setter 메서드를 통해서 memberDao 객체를 의존주입하지 않아도 된다. 스프링이 MemberDao 타입의 빈 객체를 주입하기 때문이다.

 

실행결과

실행 결과 비밀번호 변경 기능이 수행된 것을 알 수 있다. 만약 @Autowired 애노테이션을 설정한 필드에 알맞은 빈 객체가 주입되지 않았따면 ChangePasswordService의 memberDao 필드는 null일 것이다. 하지만 정상 동작 했따는 것은 @Autowired 애노테이션을 붙인 필드에 실제 MemberDao 타입의 빈 객체가 주입되었음을 의미한다.

@Autowired 애노테이션을 메서드에 설정하는 경우

  • 의존 객체 필드 멤버에 @Autowired 애노테이션을 적용하는 것과 같은 효과를 볼 수 있다.

MemberInfoPrinter.java

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();
	}
	
	//변경점 setter 메서드에 @Autowired 설정
	@Autowired
	public void setMemDao(MemberDao memDao) {
		this.memDao = memDao;
	}
	@Autowired	
	public void setPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
	
	
}

AppCtx 설정 클래스에서 infoPrinter() 메서드를 아래와 같이 수정한다.

AppCtx.java

@Configuration
public class AppCtx{
	
	@Bean
	public MemberDao memberDao() 
	{
		return new MemberDao();
	}
    
    ... 생략
	
	@Bean
	public ChangePasswordService changePwdSvc()
	{
		ChangePasswordService pwdSvc = new ChangePasswordService();
		// 의존을 주입하지 않아도 스프링이 @Autowired가 붙인 필드에
		// 해당 타입의 빈 객체를 찾아서 주입한다.
		return pwdSvc;
	}
	
	@Bean
	public MemberPrinter memberPrinter()
	{
		return new MemberPrinter();
	}
	
	... 생략
	
	@Bean
	public MemberInfoPrinter infoPrinter()
	{
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		return infoPrinter;
	}
	... 생략
}

infoPrinter() 메서드에서 MemberInfoPrinter 객체의 두 세터 메서드를 호출하지 않도록 수정했다.

 

실행결과

빈 객체의 메서드에 @Autowired 애노테이션을 붙이면 스프링은 해당 메서드를 호출한다. 이때 메서드 파라미터 타입에 해당하는 빈 객체를 찾아 인자로 주입한다.

 

@Autowired 애노테이션과 빈의 매칭

@Autowired 애노테이션을 필드나 세터 메서드에 붙이면 스프링은 타입이 일치하는 빈 객체를 찾아서 주입한다.

ChangePasswordService의 memberDao 필드의 타입은 MemberDao이므로 일치하는 타입을 가진 memberDao 빈이 주입된다. 유사하게 MemberInfoPrinter의 setMemberDao() 메서드의 memberDao 파라미터 타입이 MemberDao 클래스 타입이므로 setMemberDao() 메서드에 일치하는 타입을 가진 memberDao 빈이 주입된다.

 

MemberRegisterService 클래스의 의존 객체에게 @Autowired 애노테이션 설정

MemberRegisterService.java

public class MemberRegisterService {
	@Autowired
	private MemberDao memberDao;

	public MemberRegisterService()
	{
		
	}
	
	public MemberRegisterService(MemberDao memberDao) 
	{
		this.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();
	}
	
}

MemberListPrinter 클래스의 setter 메서드에 @Autowired 애노테이션 설정

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;
	}

	@Autowired
	public void setPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
	
	
}

AppCtx.java

@Configuration
public class AppCtx{
	
	@Bean
	public MemberDao memberDao() 
	{
		return new MemberDao();
	}
	
	@Bean
	public MemberRegisterService memberRegSvc()
	{
		return new MemberRegisterService();
	}
	
	@Bean
	public ChangePasswordService changePwdSvc()
	{
		ChangePasswordService pwdSvc = new ChangePasswordService();
		// 의존을 주입하지 않아도 스프링이 @Autowired가 붙인 필드에
		// 해당 타입의 빈 객체를 찾아서 주입한다.
		return pwdSvc;
	}
	
	@Bean
	public MemberPrinter memberPrinter()
	{
		return new MemberPrinter();
	}
	
	@Bean
	public MemberListPrinter listPrinter()
	{
		return new MemberListPrinter();
	}
	
	@Bean
	public MemberInfoPrinter infoPrinter()
	{
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		return infoPrinter;
	}
	
	@Bean
	public VersionPrinter versionPrinter()
	{
		VersionPrinter versionPrinter = new VersionPrinter();
		versionPrinter.setMajorVersion(5);
		versionPrinter.setMinorVersion(0);
		return versionPrinter;
	}
}

실행결과

References

초보 웹 개발자를 위한 스프링5 프로그래밍 입문, 최범균 저
github, https://github.com/yonghwankim-dev/spring5