ch04. 의존 자동 주입

728x90
참고 도서 : 스프링5 프로그래밍 입문 - 최범균 저

ch04. 의존 자동 주입

*3장은 명시적 의존 주입 (=설정 클래스에서 생성자 or set() 으로 의존 주입 코드 직접 작성)
*4장은 자동 의존 주입 (=@Autowired) 사용 -> 스프링 컨테이너가 알아서 해당 타입 빈 객체 가져옴

[의존 자동 주입]

-스프링이 자동으로 의존하는 빈 객체를 주입해주는 기능
-설정 클래스에 의존 주입하지 않아도 스프링이 타입 일치하는 의존 빈객체 찾아서 주입
-의존 자동 주입 설정 : @Autowired or @Resource 사용

[@Autowired 이용 의존 자동 주입]

-의존 주입 대상에 @Autowired 붙이면 된다.
-@Autowired를 필드나 set메소드에 붙이면 스프링은 타입이 일치하는 빈 객체 찾아 주입O
        -@Autowired + 필드 : 스프링이 해당 타입 빈 객체 찾아서 필드에 할당함
        -@Autowired + set메소드
                                  : 스프링은 메소드 파라미터 타입에 해당하는 빈 객체를 찾아서 인자로 주입함
-그 클래스에서 의존 빈 객체를 자동 주입했으면 해당 @Bean 설정 메소드 속에 명시적 작성했떤 의존 주입 코드는 삭제
//필드에 @Autowired

public class ChangePasswordService{
	
	@Autowired
	private MemberDao memberDao;
	
	.....
	
}
----설정 클래스 속
@Configuration
public class AppCtx{
	...
	
	@Bean
	public ChangePasswordService changePwdSvx() {
		ChangePasswordService pwdSvc = new ChangePasswordService();
		//pwdSvc.setMemberDao(memberDao()); 
		
		return pwdSvc;
	}
}
//set메소드에 @Autowired 

public class MemberInfoPrinter{
	...
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memDao = memberDao;
	}
}
----설정 클래스 속
@Configuration
public class AppCtx{
	...
	
	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		//infoPrinter.setMemberDao(memberDao()); 
		return infoPrinter;
	}
}
Q. 자동 의존 주입했는데,
A. 타입 일치하는 빈 객체 없으면 -> Exception발생
B. 타입 일치하는 빈이 2개 이상이면 -> Exception발생
          //스프링은 자동 주입 대상 타입 가진 빈을 정확하게 지정 X -> 자동주입 X

 

[자동 주입 대상 빈 정확히 지정 방법]

         ▶ [ @Qualifier 애노테이션 사용 ] : 자동 주입 대상 빈 선택 가능

          이 애노테이션은 기본적으로 두 위치에서 함께 사용해야 한다.
                  ① @Bean 빈 설정 메소드에서 한정자 지정
                  ② @Autowired 사용한 위치에서 한정자 사용하여 자동 주입할 빈 선택
                                               // , 동일한 @Qualifier(“한정자”) 를 넣어서 주입할 빈 한정함.
                                               // @Qualifier도 필드, 메소드 모두에 적용 가능O
-------------설정클래스 속-------------
@Configuration
public class 설정클래스 {
	...
	@Bean
	@Qualifier("printer") //한정값 지정 
	public MemberPrinter memberPrinter1() {
		return MemberPrinter();
	}
	
	public MemberPrinter memberPrinter1() {
		return MemberPrinter();
	}
}
----------------------------------------------
public MemberListPrinter{
	...
	@Autowired
	@Qualifier("printer") //한정값을 사용하여 자동주입할 빈 객체 선택 
	public void setMemberPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
}

 

//코드 해설
: setMemberPrinter()
메소드에 @Autowired 붙였으므로 해당 타입의 빈을 자동 주입하는데,
이때 @Qualifier로 한정자를 “printer”로 지정했으므로 -> 설정 클래스에 존재하는 동일 타입의 여러 빈 객체 중에서
@Qualifier 한정자를 “printer’로 지정한 빈이 선택되어 자동 의존 주입 된다.
Q. 만약 빈 설정에 @Qualifier 한정자 지정 따로 없으면 ?

         [ 이름으로 한정자 지정 ] : 자동 주입 대상 빈 선택 가능

-빈 설정에 @Qualifier 없으면 -> 빈 이름을 한정자로 지정함
-@Autowired 위치에 @Qualifier 없으면 -> 필드, 파라미터 이름을 한정자로 사용함
--- 설정 클래스
@Bean
public MemberPrinter printer() { //빈 이름을 한정자로 지정
return new MemberPrinter();
}

--- 해당 클래스
public class MemberInfoPrinter2{
...
@Autowired
private MemberPrinter printer; //변수 이름을 한정자로 사용
}

 

[/하위 타입 관계와 자동 주입]

-예를 들어, (public class A extends B ) B를 상속받은 A가 있다고 생각해보자.

-이 경우 A 클래스는 (하위), B 클래스는 (상위)가 된다.

-두 타입 모두를 설정 클래스에서 빈 객체로 등록했다고 치자.

-스프링 컨테이너는 B 타입 빈을 자동 주입하라는 @Autowired 태그 만나면,
                                                                A 타입의 빈과 B 타입 빈 중에서 어떤 빈을 주입할지 알 수 없다.
- , B를 상속받은 A 타입 빈 마저 자동 주입 대상의 후보가 되는 것이다.

-따라서, 상-하위 상속 관계에 있는 두 클래스 타입의 경계가 모호하므로
                   반드시 @Qaulifier 애노테이션을 붙여서 자동 주입 빈 한정짓자.

[@Autowired 필수 여부 지정 방식] : 3 가지

: 자동 주입할 대상이 필수가 아닌데, 해당 빈이 존재하지 않는 경우, Exception 처리되지 않도록 지정
3 가지 방식은 메소드/필드 모두에 그대로 적용 O

.      @Autowired(required = false)

-@Autowired required 속성을 false로 지정하면
매칭되는 빈이 없어도 예외 발생하지 않으며, 스프링은 자동 주입을 수행 X
-자동 주입할 빈이 존재하지 않으면 세터 메소드 호출 X

.      ② Optional<DateTimeFormatter> formatterOpt

-의존. 주입 대상 타입이 Optional인 경우,
       일치하는 빈 존재하지 않으면 -> 값 없는 Optional 인자를 전달
-예외 발생X

.      @Nullable

-의존 주입 대상의 파라미터에 붙이면,
자동주입이 존재하지 않을 때 -> null 인자 전달
-자동 주입할 빈이 존재하지 않아도 세터 메소드 호출 O
//메소드
@Autowired(required = false)
public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
                this.dateTimeFormatter = dateTimeFormatter;
}

@Autowired
public void setDateFormatter(Optional<DateTimeFormatter> formatterOpt) {
}

@Autowired
public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) {
                  this.dateTimeFormatter = dateTimeFormatter;
}
//필드
@Autowired(required = false)
private DateTimeFormatter dateTimeFormatter;

@Autowired
private Optional<DateTimeFormatter> formatterOpt;

@Autowired
@Nullable
private DateTimeFormatter dateTimeFormatter;

[필수 여부 지정 방식 동작의 이해]

-자동 주입 대상 필드를 기본 생성자에서 초기화함

-근데, 자동 주입 대상 빈 객체가 없는 경우,

@Autowired(required = false)
//타입 일치하는 자동 주입 대상 존재X -> 필드, 메소드에 NULL 할당 X
// -> 기본 생성자에서 초기화한 값을 출력함
//, 일치하는 빈 없으면 값 할당 자체를 하지 않음,

@Nullable
//타입 일치하는 자동 주입 대상 존재X -> NULL 할당 O

Optional<DateTimeFormatter> formatterOpt
//타입 일치하는 자동 주입 대상 존재X -> 값이 없는 Optional 할당 O

 

[자동 주입과 명시적 의존 주입 간의 관계]

Q, 설정 클래스에서 의존 주입 코드 사용했는데, 자동 주입 기능 사용하면?
A. @Autowired 자동 주입에 일치하는 빈을 우선적으로 주입함.

//웬만하면, 일관되게 사용하는 것이 좋다. 대개 작동은 하지만, 문제 생기면 복잡

//의존 자동 주입 사용 권장

 ---설정 클래스 ----------------------------
@Bean
@Qualifier("printer")
public MemberPrinter memberPrinter1() {
	
}
@Bean
public MemberPrinter memberPrinter2() {
	
}

@Bean
public MemberInfoPrinter infoPrinter() {
	MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
	infoPrinter.setPrinter(memberPrinter2()); //의존 주입 코드 
	return infoPrinter;
}

-----------------------------------------
@Autowired
@Qualifier("printer") //자동 의존 주입 사용 우선 
public void setPrinter(MemberPrinter printer) {
	this.printer=printer;
}

 

728x90