관리 메뉴

Partially Committed

[Spring] μ˜μ‘΄κ΄€κ³„ μžλ™ μ£Όμž… λ³Έλ¬Έ

πŸ’» Study !/Spring

[Spring] μ˜μ‘΄κ΄€κ³„ μžλ™ μ£Όμž…

WonderJay 2023. 1. 16. 12:52
728x90
λ°˜μ‘ν˜•
SMALL

λ‹€μ–‘ν•œ μ˜μ‘΄κ΄€κ³„ μ£Όμž…


λ‹€μ–‘ν•œ 의쑴 관계 μ£Όμž… 방법

- μƒμ„±μž μ£Όμž…

: μƒμ„±μžλ₯Ό 톡해 의쑴 관계λ₯Ό μ£Όμž… λ°›λŠ” κ²ƒμœΌλ‘œ, μƒμ„±μž 호좜 μ‹œμ μ— λ”± ν•œλ²ˆλ§Œ 호좜 λ˜λŠ” 것이 보μž₯λ˜λŠ” 것이 νŠΉμ§•μ΄λ‹€. λΆˆλ³€, ν•„μˆ˜ μ˜μ‘΄κ΄€κ³„μ— μ‚¬μš©ν•œλ‹€.

- μˆ˜μ •μž μ£Όμž…(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;
    }
    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

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

    // for test
    public MemberRepository getMemberRepository(){
        return memberRepository;
    }
}

μœ„μ™€ 같이 이전에 κ΅¬ν˜„ν–ˆμ—ˆλ‹€.

>> OrderServiceImpl ν΄λž˜μŠ€μ— @Component μ• λ…Έν…Œμ΄μ…˜μ΄ μžˆμœΌλ―€λ‘œ μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ”μ„ μ§„ν–‰ν•˜λ©°, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— OrderService ν΄λž˜μŠ€κ°€ 빈으둜 등둝이 λœλ‹€. 등둝이 될렀면 μƒμ„±μžκ°€ 호좜이 λ˜μ–΄μ•Ό ν•˜κ³ , 마침 μƒμ„±μžμ—λŠ” @Autowired μ• λ…Έν…Œμ΄μ…˜μ΄ μ‘΄μž¬ν•œλ‹€. 그러면 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ MemberRepository 와 DiscountPolicy λ₯Ό κΊΌλ‚΄μ„œ μ˜μ‘΄κ΄€κ³„λ₯Ό μ£Όμž…ν•΄μ€€λ‹€. 이와 같은 방법이 μƒμ„±μž μ£Όμž…μœΌλ‘œ 호좜 μ‹œμ μ— 단 ν•œλ²ˆλ§Œ 호좜되기 λ•Œλ¬Έμ—, λΆˆλ³€/ν•„μˆ˜ 의쑴 관계에 주둜 μ‚¬μš©λœλ‹€. 값을 μ„ΈνŒ…ν•œ λ‹€μŒμ— 더이상 λ°”λ€ŒλŠ” 것을 μ›ν•˜μ§€ μ•ŠλŠ” κ²½μš°μ—λŠ” μˆ˜μ •μž λ©”μ„œλ“œ(setter, getter)λ₯Ό λ§Œλ“€μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€.

  μœ„ OrderServiceImple μ—μ„œ μ•„λž˜μ™€ 같이 final 둜 μ„€μ •ν•œ 것을 μ•Œ 수 μžˆλ‹€.

    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;

    @Autowired
    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

  그러면 memberRepository 와 discountPolicy λŠ” λ°˜λ“œμ‹œ 값이 μ‘΄μž¬ν•΄μ•Ό ν•˜λ©°, μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ μœ„ μ½”λ“œμ—μ„œ 컴파일 였λ₯˜κ°€ λ°œμƒν•˜λ„λ‘ μ˜ˆλ°©ν•œ 것이닀.

 

* μ€‘μš”ν•œ 것은 μƒμ„±μžκ°€ 단 ν•œκ°œλ§Œ 있으면 @Autowired λ₯Ό μƒλž΅ν•˜μ—¬λ„ μžλ™ μ£Όμž…μ΄ λœλ‹€.(μŠ€ν”„λ§ λΉˆμ—λ§Œ ν•΄λ‹Ή)

 

# μˆ˜μ •μž μ£Όμž…(Setter μ£Όμž…)

- setter ν•„λ“œμ˜ 값을 λ³€κ²½ν•˜λŠ” μˆ˜μ •μž λ©”μ„œλ“œλ₯Ό ν†΅ν•΄μ„œ μ˜μ‘΄κ΄€κ³„λ₯Ό μ£Όμž…ν•œλ‹€.

- 선택, λ³€κ²½ κ°€λŠ₯성이 μžˆλŠ” 의쑴 관계에 μ‚¬μš©ν•˜λ©° μžλ°”λΉˆ ν”„λ‘œνΌν‹° κ·œμ•½μ˜ μˆ˜μ •μž λ©”μ„œλ“œ 방식을 μ‚¬μš©ν•˜λŠ” 방법이닀.

private MemberRepository memberRepository;
private DiscountPolicy discountPolicy;

@Autowired
public void setMemberRepository(MemberRepository memberRepository){
    System.out.println("memberRepository = " + memberRepository);
    this.memberRepository = memberRepository;
}
@Autowired
public void setDiscountPolicy(DiscountPolicy discountPolicy){
    System.out.println("discountPolicy = " + discountPolicy);
    this.discountPolicy = discountPolicy;
}

- μƒμ„±μž μ£Όμž…μ€ μžλ°” μŠ€ν”„λ§μ΄ λΉˆμ„ λ“±λ‘ν•˜κΈ° μœ„ν•΄ OrderService 객체λ₯Ό 생성할 λ•Œ μƒμ„±μžκ°€ 무쑰건 ν˜ΈμΆœλ˜λ―€λ‘œ, λΉˆμ— 등둝이 될 λ•Œ μ˜μ‘΄κ΄€κ³„κ°€ μ£Όμž…λ˜λ„λ‘ ν•œλ‹€.

- μˆ˜μ •μž μ£Όμž…μ€ 빈 등둝 μ‹œμ μ΄ μ•„λ‹Œ, 두 번째 단계(μ˜μ‘΄κ΄€κ³„λ₯Ό λ“±λ‘ν•˜λŠ”)μ—μ„œ μ˜μ‘΄κ΄€κ³„κ°€ λ“±λ‘λ˜λ„λ‘ ν•˜λŠ” 것이닀. 

- @Autowired λŠ” μ£Όμž…ν•  λŒ€μƒμ΄ μ—†μœΌλ©΄ 였λ₯˜κ°€ λ°œμƒν•œλ‹€. μ£Όμž…ν•  λŒ€μƒμ΄ 없어도 λ™μž‘ν•˜κ²Œ ν•˜λ €λ©΄ @Autowired(required = false) 라고 ν•˜λ©΄ λœλ‹€.

- μžλ°”λΉˆ ν”„λ‘œνΌν‹°, μžλ°”μ—μ„œλŠ” ν•„λ“œμ˜ 값을 직접 λ³€κ²½ν•˜μ§€ μ•Šκ³  setter, getter λ©”μ„œλ“œλ₯Ό 톡해 값을 읽고, λ³€κ²½ν•˜λŠ” κ·œμΉ™μ„ λ§Œλ“€μ—ˆλŠ”λ° 이λ₯Ό μžλ°”λΉˆ ν”„λ‘œνΌν‹° κ·œμ•½μ΄λΌκ³  ν•œλ‹€.

# ν•„λ“œ μ£Όμž…

- μ½”λ“œκ°€ κ°„κ²°ν•˜μ§€λ§Œ μ™ΈλΆ€μ—μ„œ 변경이 λΆˆκ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— ν…ŒμŠ€νŠΈκ°€ νž˜λ“€λ‹€.(μ€‘μš”)

- DI ν”„λ ˆμž„μ›Œν¬κ°€ μ—†μœΌλ©΄ 아무것도 ν•  수 μ—†λ‹€.

- κ·Έλƒ₯ μ‚¬μš©ν•˜μ§€ 말자. πŸ˜’

@Bean
OrderService orderService(MemberRepository memberRepository, DiscountPolicy discountPolicy){
	new OrderServiceImple(memberRepository, discountPolicy) // <----
}

(κ°„ν˜Ή μ‚¬μš©ν•˜λŠ” 경우)

- μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ‹€μ œ μ½”λ“œμ™€ κ΄€κ³„μ—†λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•  μ‹œ.

- μŠ€ν”„λ§ 섀정을 λͺ©μ μœΌλ‘œ ν•˜λŠ” @Configuration κ³Ό 같은 κ³³μ—μ„œ νŠΉλ³„ν•œ μš©λ„λ‘œ μ‚¬μš©

 

 

# 일반 λ©”μ„œλ“œ μ£Όμž…

- 일반 λ©”μ„œλ“œλ₯Ό ν†΅ν•΄μ„œ μ£Όμž…λ°›λŠ”λ‹€.

- ν•œ λ²ˆμ— μ—¬λŸ¬ ν•„λ“œλ₯Ό μ£Όμž…λ°›μ„ 수 μžˆλ‹€.

@Autowired
public void init(MemberRepository memberRepository, DiscountPolicy discountPolicy){
	this.memberRepository = memberRepository;
    this.discountPolicy = discountPolicy;
}

(μ°Έκ³ ) μ˜μ‘΄κ΄€κ³„ μžλ™ μ£Όμž…μ€ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ κ΄€λ¦¬ν•˜λŠ” μŠ€ν”„λ§ λΉˆμ΄μ–΄μ•Όμ§€λ§Œ λ™μž‘ν•˜λ©°, μŠ€ν”„λ§ 빈이 μ•„λ‹Œ Member 와 같은 ν΄λž˜μŠ€μ—μ„œ @Autowired μ½”λ“œλ₯Ό μ μš©ν•œλ‹€κ³  ν•  지라도 μ•„λ¬΄λŸ° λ™μž‘μ„ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ”λ‹€.

 

# μ˜΅μ…˜ 처리

- μ£Όμž…ν•  μŠ€ν”„λ§ 빈이 μ—†λŠ” κ²½μš°μ—λ„ λ™μž‘μ„ ν•΄μ•Ό ν•˜λŠ” 경우

- @Autowired 만 μ‚¬μš©ν•˜λ©΄ required option 의 default κ°€ true λΌμ„œ μžλ™μ£Όμž…λŒ€μƒμ΄ μ—†λŠ” κ²½μš°μ—λŠ” 였λ₯˜κ°€ λ°œμƒν•œλ‹€.

- 이에 μžλ™ μ£Όμž… λŒ€μƒμ„μ˜΅μ…˜μœΌλ‘œ μ²˜λ¦¬ν•˜λŠ” 방법은 μ•„λž˜μ™€ κ°™λ‹€.

(1) @Autowired(required=false) : μžλ™ μ£Όμž…ν•  λŒ€μƒμ΄ μ—†μœΌλ©΄ μˆ˜μ •μž λ©”μ„œλ“œ μžμ²΄κ°€ 호좜이 μ•ˆλ˜λ„λ‘ 함

(2) org.springframework.lang.@Nullable : μžλ™μ£Όμž…ν•  λŒ€μƒμ΄ μ—†μœΌλ©΄ null 이 μž…λ ₯됨

(3) Optional<> : μžλ™ μ£Όμž…ν•  λŒ€μƒμ΄ μ—†μœΌλ©΄ Optional.empty κ°€ μž…λ ₯됨.

 

public class AutowiredTest {
    @Test
    void AutowiredOption(){
        ApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
    }
    static class TestBean{
        @Autowired(required = false)
        public void setNoBean1(Member noBean1){
            // μŠ€ν”„λ§μ΄ κ΄€λ¦¬ν•˜κ³  μžˆμ§€ μ•Šμ€ 빈인 Member
            System.out.println("noBean1 = " + noBean1);
        }
        @Autowired
        public void setNoBean2(@Nullable Member noBean2){
            // μŠ€ν”„λ§μ΄ κ΄€λ¦¬ν•˜κ³  μžˆμ§€ μ•Šμ€ 빈인 Member
            System.out.println("noBean2 = " + noBean2);
        }

        @Autowired
        public void setNoBean3(Optional<Member> noBean3){
            System.out.println("noBean3 = " + noBean3);
        }
    }

}
noBean2 = null
noBean3 = Optional.empty

- μœ„ ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œ Member λŠ” μŠ€ν”„λ§ 빈이 μ•„λ‹ˆλ‹€.

- setNoBean1() 의 경우 @Autowired 의 μ˜΅μ…˜μ΄ (required=false) μ΄λ―€λ‘œ ν•΄λ‹Ή λ©”μ„œλ“œμ˜ 호좜 μžμ²΄κ°€ μ•ˆλœλ‹€.

 

# μƒμ„±μž μ£Όμž…μ„ μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” 이유

[λΆˆλ³€μ„±]

- λŒ€λΆ€λΆ„μ˜ μ˜μ‘΄κ΄€κ³„λŠ” ν•œλ²ˆ μ„€μ •λ˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ’…λ£Œ μ‹œμ κΉŒμ§€ μ˜μ‘΄κ΄€κ³„κ°€ λ³€κ²½ν•΄μ•Ό ν•  μ΄μœ κ°€ μ—†λ‹€. λ³€κ²½λ˜μ§€ μ•Šμ•„μ•Ό μ’‹λ‹€.

- μˆ˜μ •μž μ£Όμž…μ„ μ‚¬μš©ν•˜λ©΄ setter 을 public 으둜 열어두어야 ν•œλ‹€. μ΄λŠ” λˆ„κ΅°κ°€μ— μ˜ν•΄ μ˜μ‘΄κ΄€κ³„κ°€ 변경될 수 있기 λ•Œλ¬Έμ— μœ„ν—˜ν•˜λ‹€. μƒμ„±μž μ£Όμž…μ€ 객체 생성 μ‹œ 단 1번만 호좜되기 λ•Œλ¬Έμ— λΆˆλ³€ν•˜λ‹€.

 

[λˆ„λ½]

- ν”„λ ˆμž„μ›Œν¬ 없이 μˆœμˆ˜ν•œ μžλ°” μ½”λ“œλ₯Ό λ‹¨μœ„ ν…ŒμŠ€νŠΈν•  수 μžˆλ‹€.

class OrderServiceImplTest {
    @Test
    void createOrder(){
        MemoryMemberRepository memberRepository = new MemoryMemberRepository();
        memberRepository.save(new Member(1L, "name", Grade.VIP));

        OrderServiceImpl orderService = new OrderServiceImpl(memberRepository,new FixDiscountPolicy());
        Order order = orderService.createOrder(1L, "itemA", 10000);
        Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
    }
}

[final ν‚€μ›Œλ“œμ˜ μ‚¬μš© κ°€λŠ₯]

- μƒμ„±μž μ£Όμž…μ„ μ‚¬μš©ν•˜λ©΄ ν•„νŠΈμ— final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

- final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  μ‹œ, μ΄ˆκΈ°κ°’μ„ μ„€μ •ν•˜μ§€ μ•ŠμœΌλ©΄ μƒμ„±μž μ‹œμ—λ§Œ 값을 λ„£μ–΄μ£Όμ–΄μ•Ό ν•˜λ©°, final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν–ˆμ§€λ§Œ 값이 듀어가지 μ•ŠμœΌλ©΄ 컴파일 였λ₯˜κ°€ λ°œμƒν•œλ‹€.

- μƒμ„±μžμ—μ„œ 값이 μ„€μ •λ˜μ§€ μ•Šλ”λΌλ„ 컴파일 였λ₯˜κ°€ λ°œμƒν•΄μ„œ μ•ˆμ „ν•˜λ‹€.

(μ°Έκ³ ) μˆ˜μ •μž μ£Όμž…μ„ ν¬ν•¨ν•˜μ—¬ λ‚˜λ¨Έμ§€ μ£Όμž… 방식듀은 λͺ¨λ‘ μƒμ„±μž 이후에 호좜되기 λ•Œλ¬Έμ— ν•„λ“œμ— final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μ—†κ³  μƒμ„±μž μ£Όμž… λ°©μ‹λ§Œ fianl ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

 

[정리]

- μƒμ„±μž μ£Όμž… 방식은 ν”„λ ˆμž„μ›Œν¬μ— μ˜μ‘΄ν•˜μ§€ μ•Šκ³  μˆœμˆ˜ν•œ μžλ°” μ–Έμ–΄μ˜ νŠΉμ§•μ„ 잘 μ‚΄λ¦¬λŠ” 방법이닀.

- 기본적으둜 μƒμ„±μž μ£Όμž…μ„ μ‚¬μš©ν•˜λŠ” 것이 μ’‹κ³ , ν•„μˆ˜ 값이 μ•„λ‹Œ κ²½μš°μ—λŠ” μˆ˜μ •μž μ£Όμž… 방식을 μ˜΅μ…˜μœΌλ‘œ λΆ€μ—¬ν•˜λ©΄ λœλ‹€. 이와 같이 μƒμ„±μž μ£Όμž…κ³Ό μˆ˜μ •μž μ£Όμž…μ„ λ™μ‹œμ— μ‚¬μš©ν•  수 μžˆλ‹€.

- 항상 μƒμ„±μž μ£Όμž…μ„ μš°μ„ μ μœΌλ‘œ μ„ νƒν•˜λŠ” 것이 μ’‹μœΌλ©°, μˆ˜μ •μž μ£Όμž…μ€ μ˜΅μ…˜μœΌλ‘œ ν•„μš” μ‹œμ— μ„ νƒν•˜λ„λ‘ ν•˜μž. ν•„λ“œ μ£Όμž…μ€ μ‚¬μš©ν•˜μ§€ 말자.

 

# 둬볡과 μ΅œμ‹  νŠΈλ Œλ“œ

- κ°œλ°œμ„ μ§„ν–‰ν•˜λ‹€ 보면 λŒ€λΆ€λΆ„μ˜ κ²½μš°μ— λ‹€ λΆˆλ³€μ΄κ³  μ΄λŸ¬ν•œ κ²½μš°μ—λŠ”ν•„λ“œμ— final ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€. 이러면 μƒμ„±μžλ„ λ§Œλ“€μ–΄μ•Ό ν•˜κ³ , μ£Όμž… 받은 값을 λŒ€μž…ν•˜λŠ” μ½”λ“œλ₯Ό λ”°λ‘œ μž‘μ„±ν•΄μ•Ό ν•˜λŠ” λ“± μ½”λ“œμ˜ 양이 λ§Žμ•„μ§€λŠ”λ°, 이λ₯Ό νŽΈλ¦¬ν•˜κ²Œ μˆ˜ν–‰ν•  수 μžˆλŠ” 방법이 μžˆλ‹€. μ•„λž˜ μ½”λ“œλ₯Ό μ΅œμ ν™”ν•΄λ³΄μž.

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

λ¨Όμ €, μƒμ„±μžκ°€ ν•˜λ‚˜λ°–μ— μ—†μœΌλ―€λ‘œ @Autowired λ₯Ό μƒλž΅ν•  수 μžˆλ‹€.

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

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }
 }

- 그리고 이제 둬볡 라이브러리λ₯Ό μ μš©ν•΄λ³΄μž.

- 둬볡 라이브러리λ₯Ό μ‚¬μš©ν•˜λ©΄ @RequiredArgsConstructor 을 ν†΅ν•΄μ„œ fianl 이 뢙은 ν•„λ“œλ“€μ„ λͺ¨λ‘ λͺ¨μ•„μ„œ μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ λ§Œλ“€μ–΄μ€€λ‹€. 그러면 μ•„λž˜μ™€ 같이 κ°„μ†Œν™”ν•  수 μžˆλ‹€.


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

lombok 이 μžλ°”μ˜ μ• λ…Έν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ κΈ°λŠ₯을 μ‚¬μš©ν•˜μ—¬ 컴파일 μ‹œμ μ— μƒμ„±μž μ½”λ“œλ₯Ό μžλ™μœΌλ‘œ 생성해쀀닀. 😲

 

[정리]

μ΅œκ·Όμ—λŠ” μƒμ„±μžλ₯Ό 단 ν•˜λ‚˜λ§Œ λ§Œλ“€κ³  @Autowired λ₯Ό μƒλž΅ν•˜λŠ” 방법을 주둜 μ‚¬μš©ν•˜λŠ”λ°, Lombok 라이브러리의 @RequiredArgsConstructor 을 같이 μ‚¬μš©ν•˜μ—¬ μ½”λ“œλ₯Ό κΉ”λ”ν•˜κ²Œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

 

# 쑰회 빈이 2개 이상인 경우 🀨

@Autowired λŠ” Type 으둜 쑰회λ₯Ό μˆ˜ν–‰ν•œλ‹€.

그러면 @Autowired private DiscountPolicy discountPolicy 라고 ν•˜λ©΄,

ac.getBean(DiscountPolicy.class) 와 같이 μœ μ‚¬ν•˜κ²Œ λ™μž‘ν•œλ‹€.

그런데, Type 으둜 λΉˆμ„ μ‘°νšŒν•˜λ©΄ μ„ νƒλ˜λŠ” 빈이 2개 이상인 κ²½μš°κ°€ λ°œμƒν•  수 있고 μ΄λŸ¬ν•œ κ²½μš°μ—λŠ” λ¬Έμ œκ°€ λœλ‹€. DiscountPolicy 의 ν•˜μœ„ νƒ€μž…μΈ FixDiscountPolicy, RateDiscountPolicy κ°€ λ‘˜ λ‹€ μŠ€ν”„λ§ 빈으둜 μ„ μ–Έλ˜μ–΄ μžˆμ„ λ•Œ,

@Autowired private DiscountPolicy discountPolicy 와 같이 μ˜μ‘΄κ΄€κ³„ μžλ™ μ£Όμž…μ„ μ‹€ν–‰ν•˜λ©΄

 available: expected single matching bean but found 2: fixDiscountPolicy,rateDiscountPolicy

와 같은 NoUniqueBeanDefinitionException 였λ₯˜κ°€ λ°œμƒν•œλ‹€. 사싀, ν•˜μœ„νƒ€μž…μœΌλ‘œ μ§€μ •ν•˜μ—¬ ν•΄κ²°ν•  수 μžˆμ§€λ§Œ μ΄λŠ” DIP λ₯Ό μœ„λ°°ν•˜κ³  ν”„λ‘œκ·Έλž¨μ˜ μœ μ—°μ„±μ„ λ–¨μ–΄λœ¨λ¦°λ‹€. ν˜Ήμ€ μ΄λ¦„λ§Œ λ‹€λ₯΄κ³  μ™„μ „νžˆ 같은 νƒ€μž…μ˜ μŠ€ν”„λ§λΉˆμ΄ 2개 μžˆλŠ” κ²½μš°λŠ” ν•΄κ²°ν•  수 없을 것이닀. μŠ€ν”„λ§ λΉˆμ„ μˆ˜λ™μœΌλ‘œ λ“±λ‘ν•΄μ„œ 문제λ₯Ό ν•΄κ²°ν•  수 도 μžˆκ² μ§€λ§Œ, μ™Έμ˜ λ‹€μ–‘ν•œ ν•΄κ²° 방법이 μžˆλ‹€. 

 

- @Autowired ν•„λ“œ λͺ… 맀칭

- @Qulifier → @Quilifier 끼리 맀칭 → 빈 이름 맀칭

- @Primary μ‚¬μš©

 

  @Autowired ν•„λ“œ λͺ… 맀칭

@Autowired λŠ” type 으둜 맀칭을 μ‹œλ„ν•˜λŠ”λ°, μ—¬λŸ¬ 빈이 있으면 ν•„λ“œ 이름, νŒŒλΌλ―Έν„° μ΄λ¦„μœΌλ‘œ 빈 이름을 μΆ”κ°€μ μœΌλ‘œ λ§€μΉ­ν•œλ‹€. (νƒ€μž… 맀칭 μ‹œλ„λ₯Ό λ¨Όμ € ν•˜λŠ”λ°, 맀칭 κ²°κ³Όκ°€ 2개 이상이면 ν•„λ“œ λͺ…, νŒŒλΌλ―Έν„° λͺ…μœΌλ‘œ 빈 이름을 λ§€μΉ­ν•œλ‹€.)

 

  @Qualifier μ‚¬μš© (μΆ”κ°€ κ΅¬λΆ„μž)

μ£Όμž… μ‹œ 좔가적인 방법을 μ œκ³΅ν•˜λŠ” κ²ƒμž„. (빈 이름 변경이 μ•„λ‹˜!)

예λ₯Ό λ“€μ–΄, @Qualifier("mainDiscountPolicy") 라고 μ£Όμž…ν•˜λ €κ³  ν•˜λŠ”λ° λͺ»μ°ΎλŠ”λ‹€λ©΄, mainDiscountPolicy λΌλŠ” μ΄λ¦„μ˜ μŠ€ν”„λ§ λΉˆμ„ μΆ”κ°€μ μœΌλ‘œ νƒμƒ‰ν•œλ‹€. 즉 @Qualifier 은 @Qualifier 끼리 맀칭을 μ‹œλ„ν•˜κ³ , λͺ»μ°ΎλŠ”λ‹€λ©΄ 빈 이름을 λ§€μΉ­ν•˜λŠ”λ° μ—¬κΈ°μ„œλ„ λͺ»μ°ΎμœΌλ©΄ NoSuchBeanDefinitionException μ˜ˆμ™Έλ₯Ό λ°œμƒμ‹œν‚¨λ‹€. 

 

  @Primary μ‚¬μš© (μš°μ„ μˆœμœ„ μ •ν•˜κΈ°) 

@Autowired μˆ˜ν–‰ μ‹œ μ—¬λŸ¬ 개의 빈이 맀칭되면 @Primary κ°€ μš°μ„ κΆŒμ„ 가진닀. 

 

  Primary, Qualifier 의 ν™œμš©

예λ₯Ό λ“€μ–΄ μ½”λ“œμ—μ„œ λ©”μΈμœΌλ‘œ μ‚¬μš©ν•˜λŠ” λ°μ΄ν„°λ² μ΄μŠ€κ°€ 있고, μ„œλΈŒ λ°μ΄ν„°λ² μ΄μŠ€κ°€ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž. 메인 λ°μ΄ν„°λ² μ΄μŠ€μ™€μ˜ 컀λ„₯μ…˜μ„ μ–»λŠ” μŠ€ν”„λ§ λΉˆμ€ @Primary λ₯Ό μ μš©ν•˜μ—¬ @Qualifier 없이 λ””ν΄νŠΈμ²˜λŸΌ μ‘°νšŒν•  수 μžˆλ„λ‘ ν•˜κ³ , μ„œλΈŒ λ°μ΄ν„°λ² μ΄μŠ€ 컀λ„₯μ…˜ λΉˆμ„ 얻을 λ•ŒλŠ” @Qualifier 을 μ§€μ •ν•˜μ—¬ λͺ…μ‹œμ μœΌλ‘œ μ–»λŠ” λ°©λ²•μœΌλ‘œ μ½”λ“œλ₯Ό κΉ”λ”ν•˜κ²Œ μž‘μ„±ν•  수 μžˆλ‹€. μŠ€ν”„λ§μ—μ„œ 기본적으둜 μžλ™λ³΄λ‹€λŠ” μˆ˜λ™μ΄, 넓은 λ²”μœ„μ˜ μ„ νƒκΆŒλ³΄λ‹€λŠ” 쒁은 λ²”μœ„μ˜ μ„ νƒκΆŒμ΄ μš°μ„  μˆœμœ„κ°€ λ†’λ‹€. κ·Έλž˜μ„œ 이 κ²½μš°μ—μ„œλ„ λ§ˆμ°¬κ°€μ§€λ‘œ @Qualifier κ°€ μš°μ„ κΆŒμ΄ 더 λ†’λ‹€.

 

# μ‘°νšŒν•œ 빈이 λͺ¨λ‘ λ‹€ ν•„μš”ν•œ 경우

νŠΉμ • νƒ€μž…μ˜ μŠ€ν”„λ§ 빈이 λ‹€ ν•„μš”ν•œ κ²½μš°μ—λŠ” μ–΄λ–»κ²Œ λŒ€μ²˜ν• κΉŒ?

package hello.core.autowired;

import hello.core.AutoAppConfig;
import hello.core.discount.DiscountPolicy;
import hello.core.member.Grade;
import hello.core.member.Member;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;

public class AllBeanTest {
    @Test
    void findAllBean(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);

        DiscountService discountService = ac.getBean(DiscountService.class);
        Member member = new Member(1L, "userA", Grade.VIP);
        int discountPrice = discountService.discount(member, 10000, "fixDiscountPolicy");
        assertThat(discountService).isInstanceOf(DiscountService.class);
        assertThat(discountPrice).isEqualTo(1000);

        int rateDiscountPrice = discountService.discount(member, 20000, "rateDiscountPolicy");
        assertThat(rateDiscountPrice).isEqualTo(2000);
    }
    static class DiscountService{
        private final Map<String, DiscountPolicy> policyMap;
        private final List<DiscountPolicy> policies;
        @Autowired
        public DiscountService(Map<String, DiscountPolicy> policyMap, List<DiscountPolicy> policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println("policyMap = " + policyMap);
            System.out.println("policies = " + policies);
        }

        public int discount(Member member, int price, String discountCode) {
            DiscountPolicy discountPolicy = policyMap.get(discountCode);
            return discountPolicy.discount(member, price);
        }
    }
}

- DiscountService λŠ” Map 으둜 λͺ¨λ“  DiscountPolicy λ₯Ό μ£Όμž…λ°›λŠ”λ‹€. μœ„ κ²½μš°μ—λŠ” fixDiscountPolicy 와 rateDiscountPolicy κ°€ κ·Έ λŒ€μƒμ΄λ‹€.

- discount() λ©”μ„œλ“œμ˜ κΈ°λŠ₯은, discountCode 에 λ”°λΌμ„œ map μ—μ„œ ν•΄λ‹Ήν•˜λŠ” μŠ€ν”„λ§ λΉˆμ„ μ°Ύμ•„μ„œ μ‹€ν–‰ν•˜λŠ” 것이닀.

- Map<String, DiscountPolicy> λŠ” map 의 킀에 μŠ€ν”„λ§ 빈의 이름을 λ„£μ–΄μ£Όκ³ , κ·Έ κ°’μœΌλ‘œ DiscountPolicy νƒ€μž…μœΌλ‘œ μ‘°νšŒν•œ λͺ¨λ“  μŠ€ν”„λ§ λΉˆμ„ λ‹΄μ•„μ€€λ‹€.

- List<DiscountPolicy> λŠ” DiscountPolicy νƒ€μž…μœΌλ‘œ μ‘°νšŒν•œ λͺ¨λ“  μŠ€ν”„λ§ λΉˆμ„ λ‹΄μ•„μ€€λ‹€.

- λ§Œμ•½μ— ν•΄λ‹Ήν•˜λŠ” νƒ€μž…μ˜ μŠ€ν”„λ§ 빈이 μ—†μœΌλ©΄ 빈 Collection μ΄λ‚˜ Map 을 μ£Όμž…ν•œλ‹€.

 

# μžλ™, μˆ˜λ™ μ˜μ‘΄κ΄€κ³„ μ£Όμž…μ˜ μ˜¬λ°”λ₯Έ 싀무 운영 κΈ°μ€€

- μžλ™ κΈ°λŠ₯을 기본으둜 μ‚¬μš©ν•˜μž.

- 직접 λ“±λ‘ν•˜λŠ” 기술 지원 κ°μ²΄λŠ” μˆ˜λ™μœΌλ‘œ λ“±λ‘ν•˜μž.

- λ‹€ν˜•μ„±μ„ 적극 ν™œμš©ν•˜λŠ” λΉ„μ¦ˆλ‹ˆμŠ€ λ‘œμ§μ€ μˆ˜λ™ 등둝을 κ³ λ―Όν•˜μž.


Reference

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

μŠ€ν”„λ§ 핡심 원리 - 기본편 - μΈν”„λŸ° | κ°•μ˜

μŠ€ν”„λ§ μž…λ¬Έμžκ°€ 예제λ₯Ό λ§Œλ“€μ–΄κ°€λ©΄μ„œ μŠ€ν”„λ§μ˜ 핡심 원리λ₯Ό μ΄ν•΄ν•˜κ³ , μŠ€ν”„λ§ κΈ°λ³ΈκΈ°λ₯Ό ν™•μ‹€νžˆ λ‹€μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€., - κ°•μ˜ μ†Œκ°œ | μΈν”„λŸ°...

www.inflearn.com

 

728x90
λ°˜μ‘ν˜•
LIST
Comments