[SPRING] 인프런 스프링 기본편 강의 공부기록. 下 (완)

2022. 3. 7. 12:39JAVA

 의존관계 자동 주입 

 

크게 4가지로 분류한다

  • 생성자 주입
  • 수정자 주입(setter)
  • 필드 주입
  • 일반 메서드 주입

 

생성자 주입 :

@Component
public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;
    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
    discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}
  • 생성자 호출시점에 딱 1번만 호출되는 것이 보장된다.
  • 불변, 필수 의존관계에 사용
  • 생성자가 하나일 때는 @Autowired 생략 가능

 

 

수정자 주입:

@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
    @Autowired
    public void setMemberRepository(MemberRepository memberRepository) {
 	   this.memberRepository = memberRepository;
    }
    @Autowired
    public void setDiscountPolicy(DiscountPolicy discountPolicy) {
 	   this.discountPolicy = discountPolicy;
    }
}

 

  • 적용을 선택적으로 할 수 있음 (required = false)
  • set메소드가 있으므로 runtime 내에 변경 가능

 

필드 주입:

@Component
public class OrderServiceImpl implements OrderService {
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private DiscountPolicy discountPolicy;
}

 

  • 간결하지만 외부에서 변경 불가능하므로 테스트하기가 어렵다
  • DI 프레임워크에 강하게 의존한다
  • 권장 안함 (인텔리제이에서도 쓰지말라고함)
  • 테스트코드에서는 한번쯤 써도 괜찮음

 

 

 

일반 메서드 주입:

@Component
public class OrderServiceImpl implements OrderService {
    private MemberRepository memberRepository;
    private DiscountPolicy discountPolicy;
    @Autowired
    public void init(MemberRepository memberRepository, DiscountPolicy
    discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
}
  • 일반 메서드를 통해 주입 받을 수 있다
  • 일반적으로는 사용하지 않음

 

 

 

옵션 처리

 

 

//호출 안됨
@Autowired(required = false)
public void setNoBean1(Member member) {
 System.out.println("setNoBean1 = " + member);
}
//null 호출
@Autowired
public void setNoBean2(@Nullable Member member) {
 System.out.println("setNoBean2 = " + member);
}
//Optional.empty 호출
@Autowired(required = false)
public void setNoBean3(Optional<Member> member) {
 System.out.println("setNoBean3 = " + member);
}

 

  • Member는 스프링 빈으로 등록되어있지 않다.
  • setNoBean1() 은 (required=false) 이므로 호출 자체가 되지 않는다.

@Nullable, Optional은 스프링 전반에 걸쳐 지원된다. (ex. 생성자 자동 주입에서 특정 필드에만 사용하는 것 가능)

 

 

 

생성자 주입을 선택하라

 

최근에는 스프링을 포함한 DI 프레임워크 대부분이 생성자 주입을 권장한다. 

 

 

1. 불변

  • 연극이 시작되면, 배역을 맡은 배우는 바뀌지 않는다. 바뀌는 경우가 있다면 공연이 끝나고 다음 공연 사이에 일어나는 것이 정상. 꼭 바뀌어야 하는 프로그램이 있다면 설계를 다시 고민해야 한다.
  • 수정자 주입을 사용하면 set~~~() 메서드가 public 으로 열려있는 문제가 있다
  • 누군가 setter public 메서드를 사용할 수 있는 문제점

 

 

2. 누락

  • 순수 자바코드로 유연하게 테스트 가능
  • final 키워드를 사용해 의존관계 누락을 방지할 수 있다. (생성자 주입방법에서만 가능함)

 

컴파일 오류가 가장 쉽고 좋은 오류!

 

결론: 항상 생성자 주입을 사용하라. 꼭 필요하다면 수정자 주입도 선택 가능. 필드 주입은 쓰지 않는 것으로.

 

 

 

 

 

롬복과 최신 트렌드

 

build.gradle에 추가

configurations {
 compileOnly {
 extendsFrom annotationProcessor
 }
}

// dependencies
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testCompileOnly 'org.projectlombok:lombok'
    testAnnotationProcessor 'org.projectlombok:lombok'

preference - compiler - annotation processors - Enable annotation processing 활성화

 

@RequiredArgsConstructor - 생성자 자동생성. 필드주입처럼 써도 됨

 

최근 실무에서 가장 많이 쓰는 방식.

 

 

 

 

만약 조회되는 빈이 2개 이상이라면?

-> NoUniqueBeanDefinitionException 발생. 참 친절한 스프링...!

@Autowired 필드명 매칭이 필요하다.

 

 

 

 

 

 

 

2022-03-07 작성중