해당 포스터는 '초보 웹 개발자를 위한 스프링5 프로그래밍 입문' 책을 참고하였다.
1. 의존 자동 주입
2. @Autowired 애노테이션
3. @Qualifier 애노테이션
4. @Nullable 애노테이션
5. 명시적 의존 주입
예제1) 자동 주입 기능을 사용하기 전
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public ChangePasswordService changePwdSvc(){
ChangePasswordServic pwdSvc = new ChangePasswordServic();
pwdSvc.setMemberDao(memberDao()); //의존 주입
return pwdSvc;
}
예제 2) 자동 주입 기능을 사용한 후
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public ChangePasswordService changePwdSvc(){
ChangePasswordServic pwdSvc = new ChangePasswordServic(); //자동 의존 주입
return pwdSvc;
}
// 의존을 주입하지 않아도 스프링이 @Autowired가 붙인 필드에
// 해당 타입의 빈 객체를 찾아서 주입한다.
방법 1. 의존을 주입할 대상에 @Autowired 애노테이션 붙이기
//자동 의존 주입을 하기 위해
public class ChangePasswordService {
@Autowired //의존을 부입할 대상에 @Autowired 애노테이션을 붙이면 된다.
private MemberDao 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;
}
}
방법 2. Setter 메서드에 @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("데이터 없음\n");
return;
}
printer.print(member);
System.out.println();
}
@Autowired //Setter 메서드에 @Autowired 애노테이션을 붙이면 된다.
public void setMemberDao(MemberDao memberDao) { // MemberDao 타입과 일치하는 빈 객체를 찾아서 주입된다.
this.memDao = memberDao;
}
@Autowired //Setter 메서드에 @Autowired 애노테이션을 붙이면 된다.
public void setPrinter(MemberPrinter printer) {// MemberPrinter 타입과 일치하는 빈 객체를 찾아서 주입된다.
this.printer = printer;
}
}
//설정 클래스
public class AppCtx {
@Bean
public MemberDao memberDao() {
//방법 1의 memberDao 필드와 같은 타입
//방법 2의 setMemberDao() 메소드 파라미터와 같은 타입
return new MemberDao();
}
@Bean
public MemberyPrinter memberPrinter() { //방법 2의 setPrinter() 메소드 파라미터와 같은 타입
return new MemberPrinter();
}
...생략
}
주입이 되는 과정
@Autowired 애노테이션을 필드나 세터 메서드에 붙이면 스프링은 타입이 일치하는 빈 객체를 찾아서 주입한다.
방법1 ) ChangePasswordService 의 memeberDao 필드 타입은 MemberDao이므로 설정클래스(빈 객체)에서
MemberDao 타입을 가진 memberDao 빈이 주입된다.
방법 2) MemberInfoPrinter 클래스의 setPrinter() 메서드의 printer 파라미터 타입이 MemberInfoPrinter 이므로 같은
타입을 가진 설정 클래스의 memberPrinter() 메서드가 실행되면서 printer 빈이 주입된다.
방법 3. 인자 없는 기본 생성자 추가하기 + Setter 메소드에 @Autowired 애노테이션 붙이기
public class MemberListPrinter{
private MemberDao memberDao;
private MemberPrinter printer;
public MemberListPrinter(){ //인자가 없는 기본 생성자 추가
//Setter에의해 의존 자동 주입 가능
}
...생략
@Autowired //Setter 메서드에 @Autowired 애노테이선 붙이기
public void setMemberDao(MemberDao memberDao){ //MemberDao 타입과 같은 빈 객체 찾아서 주입
this.memberDao = memberDao;
}
@Autowired //Setter 메서드에 @Autowired 애노테이선 붙이기
public void setMemberPrinter(MemberPrinter printer){ //MemberPrinter 타입과 같은 빈 객체 찾아서 주입
this.printer = printer;
}
}
@Configuration
public class AppCtx{
@Bean
public MemberDao memberDao(){ //setMemberDao() 메소드의 파라미터와 같은 타입
return new MemberDao();
}
@Bean
public MemberPrinter memberPrinter(){ //setMemberPrinter() 메소드의 파라미터와 같은 타입
return new MemberPrinter();
}
..생략
}
문제 1. @Autowired에 해당하는 빈 객체가 없으면?
문제 2. @Autowired 애노테이션을 붙인 주입 대상의 타입이 일치하는 빈이 두개 이상이면?
@Bean
public MemberPrinter memberPrinter1(){
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2(){
return new MemberPrinter();
}
첫번째 위치) @Bean 애노태이션과 같이
@Configuration
pulbic class AppCtx{
...생략
@Bean
@Qualifier("printer") //해당 빈의 한정값을 "printer"로 지정
public MemberPrinter memberPrinter1(){
return new MemberPrinter();
}
@Bean
public MemberPrinter memberPrinter2(){
return new MemberPrinter();
}
}
두번째 위치) @Autowired 애노테이션과 같이
public class MemberListPrinter{
private MemberDao memberDao;
private MemberPrinter printer;
...생략
@Autowired
@Qualifier("printer") //한정 값을 "printer"로 설정
public void setMemberPrinter(MemberPrinter printer){
this.printer = printer;
}
}
1. @Bean의 경우
메서드의 이름이 한정자로 설정된다.
ex) printer() 메서드로 정의한 빈의 한정자 : @Qualifier("printer")
2. @Autowired의 경우
클래스의 필드나 메소드의 파라미터의 이름을 한정자로 설정한다.
ex)
필드 - private MemberPrinter printer 의 한정자 : @Qualifier("printer")
메소드의 파라미터 - void setMemberPrinter(MemberPrinter printer) 의 한정자 : @Qualifier("printer")
//설정 클래스
@Configuration
public class AppCtx {
@Bean
public MemberPrinter memberPrinter1() { //MemberPrinter 타입
retrun new MemberPrinter();
}
@Bean
public MemberSummerPrinter memberPrinter2() { //MemberSummerPrinter 타입
return new MemberPrinter();
}
}
해결 방법 1. @Qualifier 애노테이션 사용
//설정 클래스
@Configuration
public class AppCtx {
...생략
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
return new MemberPrinter();
}
@Bean
@Qualifier("summaryPrinter") //한정자를 summaryPrinter로 설정
public MemberSummaryPrinter memberPrinter2() {
return MemberPrinter();
}
}
//MemberListPrinter 클래스
public class MemberListPrinter {
private MemberDao memberDao;
private Memberprinter printer;
...생략
@Autowired
@Qualifier("summaryPrinter") //한정자를 summaryPrinter로 설정
public void setMemberPrinter(MemberPrinter printer) {
this.printer = printer;
}
}
해결 방법 2. 상속 관계에서 구현체의 타입을 사용
public class MemberListPrinter {
private MemberDao memberDao;
private Memberprinter printer;
...생략
@Autowired
public void setMemerPrinter(MemberSummaryPrinter printer) { //타입을 MemberSummaryPrinter로 변경
this.printer = printer;
}
}
방법 1. @Autowired(required = false) 사용하기
//메서드에 사용한 경우
public class MemberPrinter {
private DateTimeFormatter dateTimeFormatter;
@Autowired(reqired = false) //주입 대상이 없다면 setDateFormatter() 메소드는 실행하지 않는다.
public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
this.dateTimeFormatter = dateTimeFormatter;
}
}
//필드에 적용한 경우
public class MemberPrinter {
@Autowired(required=false)
private DateTimeFormatter dateTimeFormatter;
...생략
}
방법 2. Optional 사용하기
//메서드에 사용한 경우
public class MemberPrinter {
private DateTimeFormatter dateTimeFormatter;
...생략
@Autowired
public void setDateFormatter(Optional<DateTimeFormatter> formatterOpt) {
if (formatterOpt.isPresent()) { //값이 존재한다면
this.dateTimeFormatter = formatterOpt.get(); //DateTimeFormatter 타입 빈을 주입받아 필드에 할당한다.
} else { //값이 존재하지 않으면
this.dateTimeFormatter = null; //dateTimeFormatter에 null을 할당한다.
}
}
//필드에 사용한 경우
public class MemverPrinter {
@Autowired
private Optional<DateTimeFormatter> formatterOpt;
...생략
}
방법 3. @Nullable 애노테이션 사용하기
//메서드에 사용한 경우
public class MemberPrinter {
private DateTimeFormatter dateTimeFormatter;
...생략
@Autowired
public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) { //@Nullable 애노테이션 붙이기
this.dateTimeFormatter = dateTimeFormatter;
}
}
//필드에 사용한 경우
public class MemberPrinter {
@Autowired
@Nullable
private DateTimeFormatter dateTimeFormatter;
...생략
}
※ @Autowired(required = false)와 @Nullable 애노테이션의 차이점
빈칸, OX 문제
1. @Autowired 애노테이션을 이용해 의존 자동 주입을 할 수 있는데, 방식이 두가지이다. 첫번째는 (의존 주입할 대상)에 붙일 수 있고, 두번째는 (메서드)에 붙일 수 있다.
2. 자동 주입 가능한 빈이 두개 이상이면 (@Qualifier) 애노테이션을 이용하여 자동 주입 대상 빈을 한정할 수있다.
3. @Qualifier 애노테이션이 없으면 @Bean 애노테이션의 경우 (빈 이름)을 한정자로 지정하고, @Autowired 애노테이션의 경우 (필드)나 (파라미터 이름)을 한정자로 사용한다.
4. @Autowired(required=false)를 사용하였을때, 빈이 존재하지 않으면 메서드가 호출된다. (O, X)
답 : X
5. @Nullable 애노테이션과 Optional을 사용하는 방식은 빈이 존재하지 않아도 null을 인자로 받아 모두 메서드가 호출된다. (O, X)
답: O
6. 의존 주입의 우선 순위는 (@Autowired 애노테이션)을 사용하는 것이 먼저 사용된다.
7. @Autowired 애노테이션을 필드나 메서드에 붙이면 스프링은 (타입)이 일치하는 빈 객체를 찾아서 주입한다.
주관식 퀴즈
1. 아래 코드를 보고 자동으로 생성되는 @Qualifier 한정자를 쓰시오.
1번. 빈객체의 메소드
2번. 클래스의 필드
3번. 클래스의 메소드
//1.
@Bean
public MemberPrinter printer2() { //어떤 한정자?
return new MemberPrinter();
}
//2.
public class MeberListPrinter {
private MemberDao memberDao;
private MemberPrinter printer; //어떤 한정자?
@Autowired
public void setMemberPrinter(MemberPrinter printer){ //어떤 한정자?
this.printer = printer;
}
}
정답 : 1번: @Qualifier("printer2"), 2번: @Qualifier("memberDao"), 3번: @Qualifier("printer")
2. @Autowired가 필수가 아닐때 사용할 수 있는 3가지 방법 중 하나를 이용하여 코드를 고쳐보세요.
public class MemberListPrinter {
...생략
@Autowired
public void setMemberPrinter(MemberSummaryPrinter printer) {
this.printer = printer
}
}
1) @Autowired(requred=false) 사용
2) optional 사용
3) @Nullable 사용
Corner Spring #2
Editor : 스머프
[스프링2] 6장. 빈 라이프사이클과 범위 (0) | 2022.10.13 |
---|---|
[스프링2] 5장. 컴포넌트 스캔 (0) | 2022.10.13 |
[스프링2] 3장. 스프링 DI (0) | 2022.10.06 |
[스프링2] 2장. 스프링 시작하기 (1) | 2022.09.29 |
[스프링2] 1장. 들어가며 (1) | 2022.09.29 |