2021. 8. 4. 17:58ㆍCSE/Spring
1. @Autowired 애노테이션을 이용한 의존 자동 주입
- 스프링의 자동 주입 기능을 사용하면 스프링이 알아서 의존 객체를 찾아서 주입한다.
import org.springframework.beans.factory.annotation.Autowired;
public class ChangePasswordService {
@Autowired //의존을 주입할 대상에 @Autowired 애노테이션 추가
private MemberDao memberDao;
public void setMemberDao(MemberDao memberDao) {
this.memberDao = memberDao;
}
}
//스프링 설정 파일
@Configuration
public class AppCtx{
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
@Bean
public ChangePasswordService changePwdSvc(){
Change PasswordService pwdSvc = new ChangePasswordService();
//pwdSvc.setMemberDao(memberDao(); 를 하지 않아도 자동 주입 됨
return pwdSvc;
}
}
- @Autowired 애노테이션은 메서드에도 붙일 수 있다.
import org.springframework.beans.factory.annotation.Autowired;
public class MemberInfoPrinter {
private MemberDao memDao;
private MemberPrinter printer;
@Autowired
public void setMemberDao(MemberDao memberDao){
this.memDao = memberDao;
}
@Autowired
public void setPrinter(MemberPrinter printer){
this.printer = printer;
}
}
//스프링 설정 파일
@Configuration
public class AppCtx {
@Bean
public MemberDao memberDao(){
return new MemberDao();
}
//생략
@Bean
public MemberInfoPrinter infoPrinter(){
MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
//infoPrinter.setMemberDao(membeDao());
//infoPrinter.setPrinter(printer());
//없이도 자동 주입이 된다.
return infoPrinter;
}
}
- 일치하는 빈이 없거나, 일치하는 빈이 두 개 이상이면 에러가 발생한다.
2. @Qualifier 애노테이션을 이용한 의존 객체 선택
- 일치하는 빈이 두 개 이상이면 에러가 발생한다.
=> 따라서 자동 주입할 빈을 지정할 수 있어야 한다
=> @Qualifier 애노테이션을 통해 지정할 수 있다.
@Configuration
public class AppCtx{
//생략
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter(){
return new MemberPrinter();
}
@Bean MemberPrinter memberPrinter2(){
return new MemberPrinter();
}
}
public class MemberListPrinter{
private MemberDao memberDao;
private MemberPrinter printer;
//생략
@Autowired
@Qualifier("printer")
public void setMemberPrinter(MemberPrinter printer){
this.printer = printer;
}
}
3. 빈 이름과 기본 한정자
- 빈 설정에 @Qualifier 애노테이션이 없으면 빈 이름이 한정자가 된다.
@Configuration
public class AppCtx{
@Bean
public MemberPrinter printer(){
return new MemberPrinter();
}
//이 경우 한정자가 printer
@Bean
@Qualifier("mprinter")
public MemberPrinter printer2(){
return new MemberPrinter();
}
//이 경우 한정자가 mprinter
}
4. 상위/하위 타입 관계와 자동 주입
- MemberPrinter 클래스를 상속하는 MemberSummaryPrinter 클래스를 만들고 이에 대한 빈도 만들자.
public class MemberSummaryPrinter extends MemberPrinter{
@Override
public void print(Member member){
System.out.printf("회원 정보 : 이메일 = %s , 이름 = %s\n", member.getEmail(), member.getName());
}
}
package config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import spring.*;
@Configuration
public class AppCtx {
//생략
@Bean
public MemberPrinter memberPrinter(){
return new MemberPrinter();
}
@Bean
public MemberSummaryPrinter memberSummaryPrinter(){
return new MemberSummaryPrinter();
}
}
- 이 후, main()을 실행하면 일치하는 빈이 두 개 이상 발견되었을 때와 같은 에러가 발생한다
=> MemberSummaryPrinter 클래스가 MemberPrinter 클래스를 상속해서, MemberSummaryPrinter 클래스는 MemberPrinter 타입에도 할당할 수 있다.
=> 따라서 이 문제는 @Qualifer 애노테이션을 통해서 주입할 빈을 구분해주면 해결할 수 있다.
5. @Autowired 애노테이션의 필수 여부
import org.springframework.beans.factory.annotation.Autowired;
import java.time.format.DateTimeFormatter;
public class MemberPrinter {
private 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(), member.getRegisterDateTime());
}
}
@Autowired
public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter){
this.dateTimeFormatter = dateTimeFormatter;
}
}
- 위의 MemberPrinter 클래스의 print 메소드의 경우, dateTimeFormatter에 의존 객체가 주입되지 않아서 null이어도 제대로 작동한다. 하지만 이 상태로 실행을 하게 되면, 빈이 존재하지 않아서 에러가 발생하게 된다.
=> 이를 해결하는 세 가지 방법이 있다.
(1) @Autowired의 required 속성
- @Autowired의 required 속성을 false로 지정하면 매칭되는 빈이 없어도 에러가 발생하지 않고, 자동 주입을 실행하지 않는다.
@Autowired(required = false)
public void setDateTimeFormatter(DateTimeFormatter dateTimeFormatter){
this.dateTimeFormatter = dateTimeFormatter;
}
(2) 자바 8의 Optional 사용
- 스프링 5 버전 부터는 다음과 같이 Optional을 사용해도 된다.
@Autowired
public void setDateTimeFormatter(Optional<DateTimeFormatter> formatterOpt){
if (formatterOpt.isPresent(){
this.dateTimeFormatter = formatterOpt.get();
}else{
this.dateTimeFormatter = null;
}
}
(3) @Nullable 애노테이션 사용
- @Nullable 애노테이션을 의존 주입 대상 파라미터에 붙이면, 스프링 컨테이너는 자동 주입할 빈이 존재하면 해당 빈을 인자로 전달하고, 존재하지 않으면 null을 전달한다.
@Autowired
public void setDateTimeFormatter(@Nullable DateTimeFormatter dateTimeFormatter){
this.dateTimeFormatter = dateTimeFormatter;
}
* Autowired의 required 속성을 false로 할 때와 @Nullable을 사용하는 것은 뭐가 다를까?
=> Nullable을 사용하면 일치하는 빈이 없어도 해당 메소드가 실행된다는 것이다.
- 위의 세 가지 방식을 필드에도 그대로 적용할 수 있다.
@Autowired(required = false)
private DateTimeFormatter dateTimeFormatter;
@Autowired
private Optional<DateTimeFormatter> formatterOpt;
@Autowired
@Nullable
private DateTimeFormatter dateTimeFormatter;
6. 자동 주입과 명시적 의존 주입 간의 관계
- 만약 @Autowired 애노테이션이 붙여져있는 자동 주입 대상에게 의존을 명시적으로 주입하게 되면 어떻게 될까?
=> 자동 주입을 통해 일치하는 빈을 주입한다.
=> 자동주입 > 명시적 의존 주입
'CSE > Spring' 카테고리의 다른 글
[Spring5입문] AOP 프로그래밍 기초 (0) | 2021.08.09 |
---|---|
[Spring5입문] 빈 라이프사이클과 범위 (0) | 2021.08.09 |
[Spring5입문] 컴포넌트 스캔 (0) | 2021.08.08 |
[Spring5입문] 스프링 DI (0) | 2021.08.03 |
[Spring5 입문] Annotation, Singleton, AnnotationConfigApplicationContext (0) | 2021.07.21 |