[Spring] 의존 자동 주입

첫걸음 - 4

Posted by owin2828 on 2019-12-30 11:15 · 7 mins read

1. 자동 의존 주입


1-1. 자동 의존 주입?

  • 의존 주입에 필요한 객체들을 찾아 스프링이 자동으로 필드에 할당해 주는 기능
  • 스프링에서는 @Autowired@Resource 어노테이션 두 가지 방법이 존재
  • MVC 관점에서
    Component는 @Resource
    Service는 @Autowired를 주로 사용하는 추세라고 함

1-2. 자동 의존 주입 예제: Bean 객체

// ChangePasswordService.java
public class ChangePasswordService {

	@Autowired
	private MemberDao memberDao;
	...
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}

}
//AppCtx.java
@Configuration
public class AppCtx {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService();
	}

        // 아래 함수에서 의존을 주입하지 않아도 스프링이 @Autowired가 붙인 필드에
        // 해당 타입의 Bean 객체를 찾아서 주입	
	@Bean
	public ChangePasswordService changePwdSvc() {
		return new ChangePasswordService();
	}
        /* 기존 코드
	 @Bean
	 public ChangePasswordService changePwdSvc() {
	 	ChangePasswordService pwdSvc = new ChangePasswordService();
		pwdSvc.setMemberDao(memberDao());
		return pwdSvc;
	 }
        */
        ...
}
  • 기존의 코드와는 다르게 memberDao()를 통해 생성된 Bean 객체를 setter 매서드에 넘겨주지 않음

1-3. 자동 의존 주입 예제: method

// MemberInfoPrinter.java
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;
	}

}
//AppCtx.java
@Configuration
public class AppCtx {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	...
        // 원래 호출하던 두 매서드 setPrinter(), setMemberDao()를 호출하지 않음
	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		return infoPrinter;
	}
        /* 기존코드
        @Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		infoPrinter.setMemberDao(memberDao());
		infoPrinter.setPrinter(memberPrinter());
		return infoPrinter;
	}
        */
	...
}
  • @Autowired 어노테이션을 필드나 매서드에 붙이게 되면, 스프링은 타입이 일치하는 Bean 객체를 찾아서 주입
  • 만약 일치하는 Bean이나 매서드가 없는 경우, Exception이 발생하고 제대로 실행되지 않음
  • 최근에는 위와 같은 방법이 권장

1-4. 자동 주입 가능 Bean이 두 개 이상이라면?

// AppCtx.java
@Configuration
public class AppCtx {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	...
        // memberPrinter1() 매서드의 Bean의 한정 값으로 "printer"를 지정
	@Bean
	@Qualifier("printer")
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
	
	@Bean
	public MemberPrinter memberPrinter2() {
		return new MemberPrinter();
	}
	...
}
// MemberListPrinter.java
public class MemberListPrinter {

	private MemberDao memberDao;
	private MemberPrinter printer;
	...
	@Autowired
        // 앞서 스프링 설정 클래스에서 @Qualifier 어노테이션의 값으로 "printer"를 준
        // MembeerPrinter 타입의 Bean(memberPrinter1)을 자동 주입 대상으로 사용
	@Qualifier("printer")
	public void setMemberPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
}
  • @Qualifier 어노테이션을 통해 자동 주입 Bean을 지정할 수 있음
  • Bean 설정에 @Qualifier 어노테이션이 없다면, Bean의 이름을 한정자로 지정

2. @Autowired 어노테이션의 필수 여부


자동 주입할 대상이 필수가 아닌 경우(NULL값 등) 아래와 같이 세가지 방법이 존재

  1. @Autowired(required = false) 어노테이션 사용
  2. 자동 주입 대상 타입의 Optional 지정
  3. @Nullable 어노테이션 사용
  • 아래와 같이 dateTimeFormatter 필드값이 Null이어도 되는 경우 3가지 방법 예시
    // MemberPrinter.java
    public class MemberPrinter {
      private DateTimeFormatter dateTimeFormatter;
      ...
          // 차례대로 1~3번 방법의 동일 매서드 코드
          // 1번 방법
      @Autowired(required = false)
      public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
          this.dateTimeFormatter = dateTimeFormatter;
      }
    
          // 2번 방법
      @Autowired
      public void setDateFormatter(Optional<DateTimeFormatter> dateTimeFormatter) {
          this.dateTimeFormatter = dateTimeFormatter;
      }
    
          // 3번 방법
      @Autowired
      public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) {
          this.dateTimeFormatter = dateTimeFormatter;
      }
    

    각 방법의 특징은 아래와 같음 1. 매칭되는 Bean이 없어도 Exception이 발생하지 않으며 자동 주입을 수행하지 않음 2. 일치하는 Bean이 존재하지 않으면 값이 없는 Optional을 인자로 전달(Exception 발생하지 않음),
    일치하는 Bean이 존재하면 해당 Bean을 값으로 갖는 Optional을 인자로 전달 3. 스프링 컨테이너는 setter 매서드를 호출할 때 자동 주입할 Bean이 존재하면 해당 빈을 인자로 전달,
    존재하지 않으면 인자로 NULL을 전달

  • 1번 방법은 매칭되는 Bean이 없으면 매서드를 실행하지 않지만,
    2,3번 방법은 매칭되는 Bean이 없어도 해당 매서드를 실행