스프링 DI(의존성 주입) 방법

귀찮Lee·2022년 6월 19일
0

Spring

목록 보기
9/30

기본적으로 생성자 주입 DI를 구현하는 것을 추천 (맨 아랫부분 참고)

◎ 생성자 주입

  • 생성자에 @Autowired를 하면 스프링 컨테이너에 @Component로 등록된 빈에서 생성자에 필요한 빈들을 주입

  • 특징

    • 생성자 호출 시점에 딱 1번만 호출되는 것이 보장
    • 생성자가 1개만 존재하는 경우, @Autowired를 생략 가능
      • 빈에 넣을 때, 생성자를 호출하므로, 생성 할 때 같이 주입함
    • 주입받은 필드를 final로 선언 가능 (임의 변경 불가)
    • NullPointerException 을 방지
@Component
public class AServiceImpl implements AService {
    private final ARepository aRepository;
    private final AInfo aInfo;

	@Autowired // 생략 가능
	public OrderServiceImpl(ARepository aRepository, aInfo AInfo) {
    this.aRepository = aRepository;
    this.aInfo = aInfo;
  }
}

◎ 수정자 주입 (Setter 주입)

  • 필드의 값을 변경하는 수정자 메서드(set필드명 메서드)를 통해서 의존 관계를 주입하는 방법

  • 특징

    • 선택과 변경 가능성이 있는 의존 관계에 사용
    • 수정자의 경우 @Autowired 생략불가
      1. @Component가 실행하는 클래스를 생성자를 통해 스프링 빈으로 등록 (생성자가 1개이면, 해당 경우에 주입)
      2. 그 후 @Autowired가 있는 것들로 의존 관계 주입
    • 자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법
@Component
public class AServiceImpl implements AService {
    private final ARepository aRepository;
    private final AInfo aInfo;

	@Autowired 
	public void setARepository(ARepository aRepository){
        this.aRepository = aRepository;
    }
    
    @Autowired
    public void setAInfo(AInfo aInfo){
        this.aInfo = aInfo;
    }
}

◎ 필드 주입

  • 필드에 @Autowired 붙여서 바로 주입하는 방법
  • 특징
    • 코드가 간결해서 예전에 많이 사용된 방식이지만, 외부에서 변경이 불가능하여 테스트하기 힘듦
    • DI 프레임워크가 없으면 아무것도 할 수 없다. (프레임워크에 의존)
    • 실제 코드와 상관 없는 특정 테스트를 하고 싶을 때 사용할 수 있지만 정상적으로 작동되게 하려면 결국 setter가 필요하게 되서 수정자 주입을 사용하는게 더 편리해진다.
@Component
public class AServiceImpl implements AService {

    @Autowired
    private final ARepository aRepository;
    @Autowired
    private final AInfo aInfo;
}

◎ 일반 메서드 주입

  • 일반 메서드를 통해 주입하는 방법
    • 한번에 여러 필드를 주입 받을 수 있다.
    • 일반적으로 사용하지 않음

◎ 생성자 주입을 추천하는 이유

  • 불변성

    • 의존 관계 주입은 대부분 변경되지 않고 변경되서는 안된다.
    • 수정자 주입은 public 으로 열어두어야 해서 적합하지 않음
    • 생성자 주입은 객체 생성시 한번 호출되고 그 이후에는 호출 될 일이 없어 불변하게 설계 가능
  • 누락 방지

    • 생성자 주입을 사용하면 주입 데이터 누락 시 컴파일 오류가 발생하여 쉽게 누락 확인이 가능
  • field 값 final 키워드 사용 가능

    • 생성자에서 값이 설정되지 않으면 컴파일 시점에서 오류를 확인할 수 있다.
    • 나머지 주입 방식은 생성자 이후에 호출되는 형태이므로 final 키워드를 사용할 수 없다.
  • 순환 참조 방지

    • 필드 주입과 수정자 주입은 빈이 생성된 후에 참조를 하기 때문에 애플리케이션이 어떠한 오류와 경고 없이 구동됨 (호출된 후에야 오류 발생)
    • 생성자를 통해 주입하게되면 BeanCurrentlyInCreationException이 발생하게 됨

◎ 옵션 처리

  • 주입할 스프링 빈이 없을 때

    • @Autowired 의 required 옵션 기본값인 true이므로, 따로 들어갈 Bean이 없다면 오류를 발생함
    • 기본 로직으로 동작하게 하려면 일부 설정을 해주어야 한다.
  • 자동 주입 대상 옵션 처리 방법

    • @Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출되지 않게 된다.
    • org.springframework.lang.@Nullable : 자동 주입할 대상이 없으면 null이 입력된다.
    • Optional<> : 자동 주입할 대상이 없으면 Optional.empty가 입력된다.
        @Autowired(required = false)
        public void setNoBean1(User noBean1) {
            System.out.println("noBean1 = " + noBean1);
        }
    
        @Autowired
        public void setNoBean2(@Nullable User noBean2) {
            System.out.println("noBean2 = " + noBean2);
        }
    
        @Autowired
        public void setNoBean3(Optional<User> noBean3) {
            System.out.println("noBean3 = " + noBean3);
        }
profile
배운 것은 기록하자! / 오류 지적은 언제나 환영!

0개의 댓글