티스토리 뷰
초보 웹 개발자를 위한 스프링 5 프로그램 입문을 보고 복습 겸 개인 학습 정리입니다. (windows 기준)
@Autowired를 이용한 의존 자동 주입
기존 생성자 또는 메서드를 이용해 의존을 주입했었다면, @Autowired 애노테이션을 이용하면 스프링이 자동으로 빈 객체를 찾아 주입해 준다.
자동 주입할 대상이 필수가 아닌 경우 @Autowired 애노테이션의 required 속성을 false로 지정한다. @Autowired(required=false)
@Autowired 애노테이션은 메서드에도 붙일 수 있다.
예제 프로젝트 만들기 (메이븐 기준) 예제 코드
sp5-chap04 프로젝트 폴더 생성
프로젝트(sp5-chap04) 하위 폴더로 src\main\java 생성
sp5-shap04 폴더 내부에 pom.xml 생성
이클립스에서 sp5-chap04 폴더에 생성한 메이븐 프로젝트 import
기존 chap03에서 작성한 예제코드 그대로 사용 (복붙ㅎ)
※ 책에 나와있는 pom.xml파일은 메이븐 버전이 달라 프로그램이 실행이 안되니 현재 버전에 맞게 수정이 필요하다.
@Autowired 애노테이션을 이용한 의존 자동 주입
자동 주입 기능을 사용하면 스프링이 알아서 의존 객체를 찾아 주입한다.
사용 방법
의존을 주입할 대상에 @Autowired 애노테이션을 붙이면 된다.
직접 애노테이션을 붙이면 설정 클래스(AppCtx.java)에서 의존을 주입하지 않아도 된다.
필드에 @Autowired 애노테이션이 붙어 있으면 스프링이 해당 타입의 빈 객체를 찾아 필드에 할당
아래 ChangePasswordService 클래스에 직접 애노테이션을 붙였다.
→ sp5-chap04/src/main/java/spring/ChangePasswordService.java
package spring;
import org.springframework.beans.factory.annotation.Autowired;
// 사용할 애너테이션을 import
public class ChangePasswordService {
//의존을 주입할 대상에 @Autowired 붙이기
@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;
}
설정 클래스(AppCtx.java)에서 ChangePasswordService객체의 setMemberDao(memberDao()); 메서드를 호출하지 않는다.
pwdSvc.setMemberDao(memberDao()); 호출해서 MemberDao 빈 객체를 주입하지 않아도 스프링이 MemberDao 타입의 빈 객체를 주입하기 때문
→ sp5-chap04/src/main/java/config/AppCtx.java
@Configuration
public class AppCtx {
// @Bean 애노테이션은 해당 메서드가 생성한 객체를 스프링 빈이라고 설정한다.
@Bean // 이 빈은 각각의 빈 객체를 생성
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao());
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
// pwdSvc.setMemberDao(memberDao());
return pwdSvc;
}
[Run As] → [Java Application] 기존과 같이 잘 작동하는 것을 볼 수 있다.
※ 만일 @Autowired 애노테이션을 설정한 필드에 알맞은 빈 객체가 주입되지 않았다면 memberDao 필드는 null로 콘솔 실행 시 NullPointerException 발생할 것이다.
매서드에 애노테이션 붙이기
아래 MemberInfoPrinter클래스의 매개변수로 MemberDao 타입의 파라미터를 필요로 하는 메서드에 @Autowired 애노테이션을 붙였다.
→ sp5-chap04/src/main/java/spring/MemberInfoPrinter.java
package spring;
import org.springframework.beans.factory.annotation.Autowired;
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("데이터 없음");
return;
}
printer.print(member);
System.out.println();
}
@Autowired // 메서드에도 @Autowired를 붙일 수 있다.
public void setMemberDao(MemberDao memberDao) {
this.memDao = memberDao;
}
@Autowired // 메서드에도 @Autowired를 붙일 수 있다.
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
설정 클래스(AppCtx.java)에서 MemberInfoPrinter의 두 개의 세터 메서드를 호출하지 않도록 수정
→ sp5-chap04/src/main/java/config/AppCtx.java
public class AppCtx {
// @Bean 애노테이션은 해당 메서드가 생성한 객체를 스프링 빈이라고 설정한다.
@Bean // 이 빈은 각각의 빈 객체를 생성
public MemberDao memberDao() {
return new MemberDao();
}
... 생략 ...
@Bean
public MemberInfoPrinter infoPrinter() {
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
// infoPrinter.setMemberDao(memberDao());
// infoPrinter.setPrinter(memberPrinter());
return infoPrinter;
}
[Run As] → [Java Application] 누르면 이클립스 콘솔 뷰에 잘 작동하는 것을 볼 수 있다.
MemberRegisterServeice클래스와 MemberListPrinter 클래스에도 @Autowired를 설정하고, 인자가 없는 기본 생성자를 추가한다. AppCtx 클래스에서 기본 생성자를 이용하여 객체를 생성하기 위해서다.
→ sp5-chap04/src/main/java/spring/MemberRegisterServeice.java
package spring;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;;
public class MemberRegisterService {
@Autowired
private MemberDao memberDao;
// chap04 - 인자가 없는 기본생성자 추가
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();
}
}
→ sp5-chap04/src/main/java/spring/MemberListPrinter.java
package spring;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;;
public class MemberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
// chap04 - 인자가 없는 기본생성자 추가
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));
}
// chap04 - set 메서드 추가하고 애노테이션 붙임
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
public void setMemberDaoPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
설정 클래스에서 아래와 같이 의존을 주입하는 코드를 변경한다.
→ sp5-chap04/src/main/java/config/AppCtx.java
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.MemberRegisterService;
import spring.VersionPrinter;
import spring.MemberPrinter;
import spring.MemberListPrinter;
import spring.VersionPrinter;
//@Configuration은 스프링 설정 클래스를 의미함
@Configuration
public class AppCtx {
// @Bean 애노테이션은 해당 메서드가 생성한 객체를 스프링 빈이라고 설정한다.
@Bean // 이 빈은 각각의 빈 객체를 생성
public MemberDao memberDao() {
return new MemberDao();
}
@Bean
public MemberRegisterService memberRegSvc() {
return new MemberRegisterService();
}
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService();
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@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;
}
}
Error - 일치하는 빈이 없는 경우
설정 클래스에서 MemberDao빈을 주석처리하고 main 메서드 실행 시 아래와 같이 에러가 발생했다는 내용이 나온다.
org.springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyExceptio n: Error creating bean with name 'memberRegSvc': Unsatisfied dependency expressed through field 'memberDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'spring.MemberDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberRegSvc': Unsatisfied dependency expressed through field 'memberDao'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'spring.MemberDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
→ memberRegisterService 필드에 주입할 MemberDao 빈이 존재하지 않아 에러가 발생했다는 것을 알려준다.
Error - 빈이 두 개 이상인 경우
설정 클래스에서 MemberPrinter에 해당하는 빈을 여러 개 만들고 main 메서드 실행 시 아래와 같이 에러가 발생했다는 내용이 나온다.
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyExceptio n: Error creating bean with name 'listPrinter': Unsatisfied dependency expressed through method 'setMemberDaoPrinter' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'spring.MemberPrinter' available: expected single matching bean but found 3: memberPrinter, memberPrinter1, memberPrinter2
→ MemberPrinter 타입의 빈을 한정할 수없다고 일치하는 빈이 한 개가 아니라 memberPrinter, memberPrinter1, memberPrinter2인 세 개의 빈을 발견했다는 것을 알려준다.
@Qualifier 애노테이션
자동 주입 가능한 빈이 두 개 이상일 때 @Qualifier 애노테이션을 사용한다.
@Qualifier 애노테이션을 사용하면 자동 주입 대상 빈을 한정할 수 있다.
error 예제를 그대로 사용해서 설정 클래스(AppCtx)에 중복으로 들어간 MemberPrinter부분에 한 개의 빈에 @Qualifier 애노테이션에 ("printer")를 붙여준다. 이 "printer"는 한정 값이 "printer"인 빈을 의존 주입 후보로 사용한다.
→ sp5-chap04/src/main/java/config/AppCtx.java
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2() {
return new MemberPrinter();
}
MemberListPrinter 클래스와 MemberInfoPrinter 클래스에 설정했던 @Autowired 애너테이션 아래에
@Qualifier 애노테이션을 붙인다.
→ sp5-chap04/src/main/java/spring/MemberListPrinter.java
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
@Qualifier("printer") // 추가
public void setMemberDaoPrinter(MemberPrinter printer) {
this.printer = printer;
→ sp5-chap04/src/main/java/spring/MemberInfoPrinter.java
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memDao = memberDao;
}
@Autowired
@Qualifier("printer") // 추가
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
[Run As] → [Java Application] 누르면 이클립스 콘솔 뷰에 잘 작동하는 것을 볼 수 있다.
※만약 한 클래스라도 @Qualifier를 설정하지 않으면 NoUniqueBeanDefinitionException 오류가 발생한다.
빈 이름과 기본 한정자 (?접근 제한자?)
빈 설정에 @Qualifier 애노테이션이 없으면 빈의 이름을 한정자로 지정한다.
pinter() 메서드로 정의한 빈의 한정자는 빈의 이름인 "printer"가 되고
printer2() 메서드로 정의한 빈의 한정자는 @Qualifier 애너테이션에 지정된 "mprinter"가 된다. 빈의 이름은 "printer2"
@Autowired 애너테이션 또한 @Qualifier 애너테이션이 없으면 필드나 파라미터 이름을 한정자로 사용한다.
@Configuration
public class AppCtx2 {
@Bean
public MemberPrinter printer() { // 빈 이름은 printer
return new MemberPrinter(); // 빈 한정자는 빈 이름인 printer
}
@Bean
@Qualifier("mprinter")
public MemberPrinter printer2() { // 빈 이름은 printer2
return new MemberPrinter(); // 빈 한정자는 애너테이션에 설정한 mprinter
}
}
빈 이름 | @Qualifier | 한정자 |
printer | printer | |
printer2 | mprinter | mprinter |
'study > Spring' 카테고리의 다른 글
chap 07 - AOP 프로그래밍 (0) | 2023.01.10 |
---|---|
chap 06 - 빈 라이프사이클 & 범위 (0) | 2023.01.09 |
chap 05 - 컴포넌트 스캔 (0) | 2023.01.05 |
chap 03 - 스프링 DI (Dependency injection) (0) | 2022.12.05 |
환경 변수 설정 (windows 기준으로 설치) (0) | 2022.11.29 |
- Total
- Today
- Yesterday
- git
- Java
- 회원가입
- 디자인 패턴
- 면접을 위한 CS 전공 지식 노트
- django
- error: failed to push some refs to 'https://github.com/
- 한글 형태소 분석기
- Python
- 검색 결과 내 페이지네이션
- authenticate()
- git공부
- 혼자 공부하는 파이썬
- git 공부
- Spring
- django-environ
- 회원 로그인
- 배열
- API
- 커맨드 객체
- 톰캣
- django.contrib.auth
- 웹페이지
- Magazine K
- musma
- Django tutorial
- python3
- 암호화
- 환경 변수 설정
- path variable
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |