의존관계 자동 주입

<aside> ❗

다양한 의존관계 주입 방법

<aside> ❗

생성자 주입

[특징]

package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@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;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        // 주문 서비스 입장에서 할인에 대한 것 모르겠다. discountPolicy 니가 알아서 해줘 - 단일 책임 원칙을 잘 지킨 것
        // 즉, 할인 변경을 수행할 때, 할인 쪽만 고치면 됨
        // member 전체를 넘겨도 되고, 등급만 넘겨도 된다. - 상황에 맞게 구현하면 됨
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }

    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

[기타 팁]

좋은 개발은 한계점이랑 제약이 있어야 한다. 가급적 생성자에 값을 넣고 Setter 메서드를 안 만드는게 좋다. → 버그가 줄어든다.

관례상 생성자의 인자는 웬만하면 값을 다 넣어야 한다.

</aside>

<aside> ❗

수정자 주입 (Setter)

[특징]

package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@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;
		}
		
		@Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
		
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        // 주문 서비스 입장에서 할인에 대한 것 모르겠다. discountPolicy 니가 알아서 해줘 - 단일 책임 원칙을 잘 지킨 것
        // 즉, 할인 변경을 수행할 때, 할인 쪽만 고치면 됨
        // member 전체를 넘겨도 되고, 등급만 넘겨도 된다. - 상황에 맞게 구현하면 됨
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }

    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}

[참고]

  1. 스프링 빈들을 등록한다.
  2. 의존관계를 자동으로 주입 (@Autowired가 붙으면 자동으로 주입)

중요 !!

<aside> ❗

필드 주입

[특징]

package hello.core.order;

import hello.core.discount.DiscountPolicy;
import hello.core.member.Member;
import hello.core.member.MemberRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class OrderServiceImpl implements OrderService{
		// 필드에 바로 주입 
    @Autowired
    private MemberRepository memberRepository;
    @Autowired
    private DiscountPolicy discountPolicy;

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        // 주문 서비스 입장에서 할인에 대한 것 모르겠다. discountPolicy 니가 알아서 해줘 - 단일 책임 원칙을 잘 지킨 것
        // 즉, 할인 변경을 수행할 때, 할인 쪽만 고치면 됨
        // member 전체를 넘겨도 되고, 등급만 넘겨도 된다. - 상황에 맞게 구현하면 됨
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }

    public MemberRepository getMemberRepository() {
        return memberRepository;
    }
}
@Bean
OrderService orderService(MemberRepository memberRepoisitory, DiscountPolicy
discountPolicy) {
return null;
}

[참조]

<aside> ❗

일반 메서드 주입

[특징]

@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;
	}
}

<aside> ❗

참고

<aside> ❗

옵션 처리

[자동 주입 대상을 옵션으로 처리하는 방법]

** 여기서 Member는 스프링 빈이 아닌 자바 순수 객체 **

// 의존관계가 없으면 해당 메서드 자체를 호출하지 않음
        @Autowired(required = false)
        public void setNoBean1(Member noBean1) {
            System.out.println("noBean1 = " + noBean1);
  }
@Autowired
        public void setNoBean2(@Nullable Member noBean2) {
            System.out.println("noBean2 = " + noBean2);
        }
@Autowired
        public void setNoBean3(Optional<Member> noBean3) {
            System.out.println("noBean3 = " + noBean3);
        }

결과

noBean2 = null
noBean3 = Optional.empty

[참고]

<aside> ❗

생성자 주입을 선택하라

불변

누락

final 키워드 사용

[참고]

<aside> ❗

정리

<aside> ❗

롬복과 최신 트랜드

@Getter @Setter @toString

@RequiredArgsConstructor

<aside> ❗

정리