06번 글 ( https://simfairy.tistory.com/282 ) 이어서 함
- 정리
초기화가 필요한 메서드나 객체들은 생성자 주입이 낫다
chap03 복사
- 탐색기에서 복사. 폴더이름은 chap03_copy
- pom.xml : groupId, artifactId 을 chap04로 변경
- chap03_copy프로젝트 maven import
- 프로젝트이름변경 chap04
1. @Autowired 애너테이션을 이용한 자동 주입
- ChangePasswordService : MemberDao를 주입 받음
- setMemberDao메서드에 @Autowired 추가 (세터 자동 주입)
- AppCtx 의존주입설정
- pwdSvc.setMemberDao(memberDao()); // 삭제
- MemberInfoPrinter
- setMemberDao, setMemberPrinter 메서드에 @Autowired 추가
- 필드 자동 주입
- MemberInfoPrinter
- MemberListPrinter
- MemberRegisterService
- 필드에 @Autowired 추가
- VersionPrinter
- @Value로 기본타입 값 주입
2. 일치하는 빈이 없는 경우
- AppCtx에서 MemberDao빈 주석 처리
- 회원가입 테스트 후 예외 확인
- UnsatisfiedDependencyException 예외 발생
- ChangePasswordService빈을 생성하려면 반드시 MemberDao빈을 주입받아야 하는데
MemberDao빈이 존재하지 않아 ChangePasswordService빈을 생성할 수 없음
- NoSuchBeanDefinitionException
- 검색 대상의 스프링빈이 정의되지 않음
3. @Autowired 애너테이션을 붙인 주입 대상에 일치하는 빈이 두 개 이상인 경우
- AppCtx에서 MemberPrinter빈 2개 정의 : memberPrinter1, memberPrinter2
- NoUniqueBeanDefinitionException 예외 발생
4. @Qualifier 애너테이션을 이용한 의존 객체 선택
- MemberInfoPrinter
- MemberListPrinter
- MemberPrinter 필드에 @Qualifier("printer") 추가
- AppCtx
- MemberInfoPrinter빈 설정 @Qualifier("printer") 추가
5. @Autowired required 속성
- 기본값 : true 의존객체가 억으면 빈을 생성하지 않음
- false : 의존객체가 없어도 빈을 생성함
- MemberPrinter 수정
- MainForSpring 상단 정리
애노테이션 방식만 남기고 나머지 ctx는 삭제나 주석걸기
public class MainForSpring {
`
`
`
`
// 애노테이션 방식
ctx = new AnnotationConfigApplicationContext(AppCtx.class);
}
- @Autowired 애너테이션을 이용한 자동 주입
- AppCtx에서 ChangePasswordService빈에 세터 주입부분을 주석 걸고
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 MemberRegisterService memberRegSvc() {
return new MemberRegisterService(memberDao()); // 생성자 주입
}
@Bean
public ChangePasswordService changePwdSvc() {
ChangePasswordService pwdSvc = new ChangePasswordService();
// pwdSvc.setMemberDao(memberDao()); // 세터(수정자) 주입
return pwdSvc;
}
@Bean
public MemberPrinter memberPrinter() {
return new MemberPrinter();
}
@Bean
public MemberListPrinter memberListPrinter() {
// 생성자 주입
return new MemberListPrinter(memberDao(), memberPrinter());
}
@Bean
public MemberInfoPrinter memberInfoPrinter() {
MemberInfoPrinter memberInfoPrinter = new MemberInfoPrinter();
// 세터(수정자) 주입, Setter DI(Dependency Injection)
memberInfoPrinter.setMemberDao(memberDao());
memberInfoPrinter.setPrinter(memberPrinter());
return memberInfoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
return new VersionPrinter().setMajorVersion(5).setMinorVersion(0);
}
}
MainForSpring에서 실행하면 null발생 - memberDao 주입이 되지않기 때문에 null
- ChangePasswordService 클래스로 가서
세터 주입 부분에 @Autowired를 붙여주고 메인에서 실행해보자
package spring;
import org.springframework.beans.factory.annotation.Autowired;
public class ChangePasswordService {
private MemberDao memberDao;
// 세터(수정자) 주입
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.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); // 업데이트
}
}
- 필드 자동 주입
- MemberInfoPrinter
@Autowired 추가
package spring;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberInfoPrinter {
private MemberDao memberDao;
private MemberPrinter printer;
@Autowired
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
@Autowired
public void setPrinter(MemberPrinter printer) {
this.printer = printer;
}
public void printMemberInfo(String email) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
}
- AppCtx
MemberInfoPrinter 세터 주입부분 두가지 주석
@Configuration
public class AppCtx {
`
`
`
`
@Bean
public MemberInfoPrinter memberInfoPrinter() {
MemberInfoPrinter memberInfoPrinter = new MemberInfoPrinter();
// 세터(수정자) 주입, Setter DI(Dependency Injection)
// memberInfoPrinter.setMemberDao(memberDao());
// memberInfoPrinter.setPrinter(memberPrinter());
return memberInfoPrinter;
}
@Bean
public VersionPrinter versionPrinter() {
return new VersionPrinter().setMajorVersion(5).setMinorVersion(0);
}
}
메인에서 테스트
- MemberInfoPrinter
필드에 @Autowired 추가 하고 set 두가지 메서드는 주석
package spring;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberInfoPrinter {
@Autowired
private MemberDao memberDao;
@Autowired
private MemberPrinter printer;
// public void setMemberDao(MemberDao memberDao) {
// this.memberDao = memberDao;
// }
//
//
// public void setPrinter(MemberPrinter printer) {
// this.printer = printer;
// }
public void printMemberInfo(String email) {
Member member = memberDao.selectByEmail(email);
if(member == null) {
System.out.println("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
}
테스트 실행
- config 패키지 test01, test02 패키지 삭제
- src/main/resources 안에 test01, test02, appCtx.xml 삭제
MainForSpring - ctrl + shift + o 를 눌러 임포트 삭제
- AppCtx
MemberRegisterService(memberDao); <-- 괄호안에 memberDao 삭제
빨간줄이 뜰것이다
MemberRegisterService 마우스를 올리고 F3으로 들어간다
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 MemberRegisterService memberRegSvc() {
return new MemberRegisterService(); // 생성자 주입
}
}
- MemberRegisterService 클래스
상단에 기본 생성자 하나 생성
필드에 @Autowired 추가
package spring;
import java.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberRegisterService {
@Autowired
private MemberDao memberDao;
public MemberRegisterService() {
}
public MemberRegisterService(MemberDao memberDao) {
this.memberDao = memberDao;
}
`
`
`
`
}
- AppCtx
return new MemberListPrinter(memberDao(), memberPrinter()); 괄호안에 메소드 삭제
@Configuration
public class AppCtx {
`
`
`
`
@Bean
public MemberListPrinter memberListPrinter() {
// 생성자 주입
return new MemberListPrinter();
}
`
`
`
}
- MemberListPrinter
기본 생성자 만들고 필드에 @Autowired 추가
package spring;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberListPrinter {
@Autowired
private MemberDao memberDao;
@Autowired
private MemberPrinter printer;
public MemberListPrinter() {
}
`
`
`
}
- AppCtx
return new VersionPrinter().setMajorVersion(5).setMinorVersion(0);
뒤쪽 set 부분 다 삭제
@Configuration
public class AppCtx {
`
`
`
@Bean
public VersionPrinter versionPrinter() {
return new VersionPrinter();
}
}
- VersionPrinter
필드에 @Value로 버전 정보 넣기
package spring;
import org.springframework.beans.factory.annotation.Value;
public class VersionPrinter {
@Value("5")
private int majorVersion;
@Value("0")
private int minorVersion;
`
`
`
`
}
- 일치하는 빈이 없는 경우
- AppCtx
상단 MemberDao 주석
ChangePasswordService pwdSvc = new ChangePasswordService(); 이부분을
return new ChangePasswordService(); 형태로 변경
@Configuration
public class AppCtx {
// @Bean
// public MemberDao memberDao() {
// return new MemberDao();
// }
`
`
`
@Bean
public ChangePasswordService changePwdSvc() {
return new ChangePasswordService();;
}
`
`
`
}
실행하고 예외 확인하기
UnsatisfiedDependencyException 예외
NoSuchBeanDefinitionException 예외
- @Autowired 애너테이션을 붙인 주입 대상에 일치하는 빈이 두 개 이상인 경우
- AppCtx에서
다시 MemberDao의 주석을 풀어주고
MemberPrinter 복사해서 두개를 만들어서 각각 1, 2 를 붙여주고 원본은 주석 걸고 메인 실행
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
`
`
`
// @Bean
// public MemberPrinter memberPrinter() {
// return new MemberPrinter();
// }
@Bean
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2() {
return new MemberPrinter();
}
`
`
`
`
}
NoUniqueBeanDefinitionException 예외 확인
- @Qualifier 애너테이션을 이용한 의존 객체 선택
- AppCtx
memberPrinter1상단에 @Qualifier("printer") 붙여줌
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao() {
return new MemberDao();
}
`
`
`
// @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 클래스
필드중 private MemberPrinter printer 상단에 각각 @Qualifier("printer") 붙여준다
public class MemberListPrinter {
@Autowired
private MemberDao memberDao;
@Autowired
@Qualifier("printer")
private MemberPrinter printer;
public MemberListPrinter() {
}
`
`
`
}
- MemberInfoPrinter
public class MemberInfoPrinter {
@Autowired
private MemberDao memberDao;
@Autowired
@Qualifier("printer")
private MemberPrinter printer;
`
`
`
`
}
- AppCtx
memberPrinter2 의 이름을 printer로 바꾸고 메인에서 테스트 해본다
@Configuration
public class AppCtx {
`
`
`
`
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
public MemberPrinter printer() {
return new MemberPrinter();
}
`
`
`
`
}
- spring 패키지 MemberPrinter 클래스 수정
@Autowired(required = false) 붙이고 실행
package spring;
import java.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
public class MemberPrinter {
private DateTimeFormatter dateTimeFormatter;
public MemberPrinter() {
dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
}
@Autowired(required = false)
public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}
public void print(Member member) {
if (dateTimeFormatter == null) {
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n",
member.getId(), member.getEmail(),
member.getName(), member.getRegisterDateTime());
} else {
System.out.printf(
"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n",
member.getId(), member.getEmail(),
member.getName(),
dateTimeFormatter.format(member.getRegisterDateTime()));
}
}
}
메인에서 테스트 실행
'학습 > SPRING' 카테고리의 다른 글
14. 스프링 - mybatis 기본 설정 (0) | 2023.01.05 |
---|---|
13. 스프링 - Paging (0) | 2022.12.30 |
06. 스프링 - 두 개 이상의 설정 파일 사용하기 (0) | 2022.12.21 |
04. 스프링 DI : 생성자 방식 (0) | 2022.12.21 |
03. 스프링 DI - 애노테이션 방식, XML 방식 (0) | 2022.12.19 |
댓글