Java/JavaSpring

Chap 4. 의존 자동 주입

펭킹 2022. 6. 20. 12:17

@Autowire 애노테이션을 이용한 의존 자동 주입

자동 주입 기능을 사용하면 스프링에서 데이터 타입에 맞춰 의존객체(빈(Bean) 객체)를 찾아 주입한다.

@Autowired 애노테이션은 메서드에도 붙일 수 있다. 

 

@Qualifier 애노테이션을 이용한 의존 객체 선택

자동 주입 가능한 빈이 두 개 이상이면 자동 주입할 빈을 지정할 수 있는 방법이 필요하다. 이때 @Qualifier를 사용한다. 이것은 주입 대상 빈을 한정하기 위해 사용한다.

 

@Configuration
public class AppCtx {

	@Bean
	@Qualifier("printer")
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
	
	@Bean
	public MemberPrinter memberPrinter2() {
		return new MemberPrinter();
	}

 

public class MemberListPrinter {

	private MemberDao memberDao;
	private MemberPrinter printer;

	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	
	@Autowired
    	@Qualifier
	public void setPrinter(MemberPrinter printer) {
		this.printer = printer;
	}

 

MemberPrinter가 2개이므로 setPrinter에서 어떤 프린터를 써야될지 자동으로 판단할 수가 없다. 하지만 @Qualifier를 사용하면 memberPrinter1과 setPrinter가 이어지도록 설정 할 수 있다.

@Autowired 애노테이션을 필드와 메서드에 모두 적용 할 수 있으므로 @Qualifier 애노테이션도 필드와 메서드에 적용가능하다.

 

빈 설정에 @Qualifier가 없으면 빈 이름을 한정자로 지정한다.

 

@Configuration
public class AppCtx {
	
	@Bean
	public MemberPrinter printer1() {
		return new MemberPrinter();
	}
    
    	@Bean
    	@Qualifier("mprinter")
	public MemberPrinter printer2() {
		return new MemberPrinter();
	}

 

printer1() 메서드의 빈 한정자는 빈 이름인 " printer1"가 되고, printer2() 빈은 @Qualifier 애노테이션 값은 "mprinter"가 한정자가 된다.

 

상위 / 하위 타입관계와 자동 주입

상속 시 자식 클래스도 부모 클래스 타입에 포함된다. 즉, 부모의 클래스 타입이 자식의 클래스 타입이 되어 @Qualifier와 같은 한정자가 없을 때, @Autowired를 할 때 데이터 타입이 같은 객체가 2개로 인식되어 오류가 발생한다. 따라서 부모 자식간의 상속이 발생한 경우 한정자를 필수적으로 사용해야된다.

 

@Autowired 애노테이션 필수 여부

다음은 dateTimeFormatter 필드의 null 여부에 따라 날짜형식이 다르게 출력되는 코드이다.

 

public class MemberPrinter {
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() 
	{
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}

	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()));
		}
	}
	
	@Autowired(required = false)//함수를 실행하지 않아 기본생성자 초기화 값을 null로 생성하지 않는다.
	public void setDateFormatter(DateTimeFormatter dateTimeFormatter)
	{
		this.dateTimeFormatter = dateTimeFormatter;
	}
	
//	@Autowired
//	public void setDateFormaatter(@Nullable DateTimeFormatter dateTimeFormatter)//함수를 실행하고 확인하여 bean이 없으면 기본생성자 초기화 값이 null이 된다.
//	{
//		this.dateTimeFormatter = dateTimeFormatter;
//	}
}

 

@Autowired 애노테이션은 기본적으로 @Autowired 애노테이션을 붙인 타입에 해당하는 빈이 존재하지 않으면 오류가 발생한다.

필수여부 지정에는 크게 2가지가 있다. (Optional까지 포함하면 3가지지만, 다루지 않겠다.)

첫번째는 @Autowired 애노테이션의 required 속성을 false로 지정하는 것이다. 다음과 같이 설정을 하면 함수 자체를 실행 하지 않아서 위 예제의 this.dateTimeFormatter에 값이 들어가지 않아 yyyy년 MM월 dd일의 형식으로 출력된다.

두번째는 @Nullable 애노테이션을 사용하는 것이다. 다음과 같이 설정하면 자동 주입할 빈이 존재하지 않아도 함수를 실행하여 위 예제의 this.dateTimeFormatter에 null값이 들어가서 yyyy-MM-dd의 형식으로 출력된다.

 

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

설정 클래스에서 의존 주입(setter)을 하고, 자동 주입 대상(@Autowired)이 되면 주입이 2번 발생한 것으로 간주한다. 하지만 @Autowired 애노테이션이 우선권을 가진다.

의존주입과 자동 주입을 섞어서 사용하면 휴먼에러가 발생할 가능성이 매우 높으므로 스프링에서 제공하는 자동 주입 기능(@Autowired)으로 통일하는것을 추천한다.