[Spring ๊ธฐ๋ณธ] 7. ์์กด ๊ด๊ณ ์๋ ์ฃผ์
์๋ ํ์ธ์!
์ด๋ฒ ์น์ ์ ์ด์์ฒญ ๊ธธ์ด์ฅ..ใ ใ ์ค๋ ๊ฑธ๋ฆด ์์ ..ใ
๊ทธ๋ผ ์์ํด ๋ณผ๊ฒ์! ๊ณ ๊ณ !!

1. ๋ค์ํ ์์กด ๊ด๊ณ ์ฃผ์ ๋ฐฉ๋ฒ
์์กด ๊ด๊ณ ์ฃผ์ ์ ํฌ๊ฒ 4๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
- ์์ฑ์ ์ฃผ์
- ์์ ์ ์ฃผ์ (setter ์ฃผ์ )
- ํ๋ ์ฃผ์
- ์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
1-1. ์์ฑ์ ์ฃผ์ โญ
์ด๋ฆ ๊ทธ๋๋ก ์์ฑ์๋ฅผ ํตํด์ ์์กด ๊ด๊ณ๋ฅผ ์ฃผ์ ๋ฐ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
์ง๊ธ๊น์ง ์ ๊ฐ ์งํํ๋ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก ์์ฑ์ ์ฃผ์ ์ ๋๋ค.
<ํน์ง>
1. ์์ฑ์ ํธ์ถ ์์ ์ ๋ฑ 1๋ฒ๋ง ํธ์ถ๋๋ ๊ฒ์ด ๋ณด์ฅ๋ฉ๋๋ค. (์ฃผ๋ก ์ฌ์ฉ)
2. ๋ถ๋ณ, ํ์ ์์กด ๊ด๊ณ์ ์ฌ์ฉํฉ๋๋ค.
@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;
}
...
}
์์ฑ์ ์ฃผ์ ์ด ์ด๋ ๊ฒ ๋์ด์๋๋ฐ, ์ด๊ฑด ๋ถ๋ณ, ํ์๋ก ๋ง๋ค์ด๋์ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ public์ผ๋ก ๊ฐ์ ๋ฐ๊พธ๊ฑฐ๋ ํ ์ ์์ต๋๋ค.
- private final = ์์ฑ์์์ ๋ค์ด์จ ๊ฐ์ด ๋ฌด์กฐ๊ฑด ์์ด์ผ ํ๋ค. (์์ฑ์์๋ ๊ฐ์ ์ฑ์๋ฃ์ด์ผ ํจ), ํ์
์ค์!! ์์ฑ์๊ฐ ๋ฑ 1๊ฐ๋ง ์์ผ๋ฉด @Autowired๋ฅผ ์๋ตํด๋ ์๋ ์ฃผ์ ๋ฉ๋๋ค.
๋ชฐ๋ก , ์คํ๋ง ๋น์๋ง ํด๋นํฉ๋๋ค.

1-2. ์์ ์ ์ฃผ์ (setter ์ฃผ์ )
setter๋ผ ๋ถ๋ฆฌ๋ ํ๋์ ๊ฐ์ ๋ณ๊ฒฝํ๋ ์์ ์ ๋ฉ์๋๋ฅผ ํตํด์ ์์กด ๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
<ํน์ง>
1. ์ ํ์ , ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ์๋ ์์กด ๊ด๊ณ์ ์ฌ์ฉํฉ๋๋ค. (๊ฐ๋ ์ฌ์ฉ)
2. ์๋ฐ๋น ํ๋กํผํฐ ๊ท์ฝ์ ์์ ์ ๋ฉ์๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
@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์ ๊ธฐ๋ณธ ๋์์ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ฃผ์ ํ ๋์์ด ์์ด๋ ๋์ํ๊ฒ ํ๋ ค๋ฉด @Autowired(required = false)๋ก ์ง์ ํ๋ฉด ๋ฉ๋๋ค.
์ฐธ๊ณ !! ์๋ฐ๋น ํ๋กํผํฐ, ์๋ฐ์์๋ ๊ณผ๊ฑฐ๋ถํฐ ํ๋์ ๊ฐ์ ์ง์ ๋ณ๊ฒฝํ์ง ์๊ณ , setXxx, getXxx๋ผ๋ ๋ฉ์๋๋ฅผ ํตํด์ ๊ฐ์ ์ฝ๊ฑฐ๋ ์์ ํ๋ ๊ท์น์ ๋ง๋ค์๋๋ฐ, ๊ทธ๊ฒ์ด ์๋ฐ๋น ํ๋กํผํฐ ๊ท์ฝ์ ๋๋ค,
<์๋ฐ๋น ํ๋กํผํฐ ๊ท์ฝ ์์>
class Data {
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}

1-3. ํ๋ ์ฃผ์
์ด๋ฆ ๊ทธ๋๋ก ํ๋์ ๋ฐ๋ก ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
<ํน์ง>
1. ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ ๋ง์ ๊ฐ๋ฐ์๋ค์ ์ ํนํ์ง๋ง, ์ธ๋ถ์์ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํด์ ํ ์คํธ๊ฐ ํ๋ค๋ค๋ ์น๋ช ์ ์ธ ๋จ์ ์ด ์์ต๋๋ค.
2. DI ํ๋ ์์ํฌ๊ฐ ์์ผ๋ฉด ์๋ฌด ๊ฒ๋ ํ ์ ์์ต๋๋ค.
3. ๊ฒฐ๋ก ์ ์ฌ์ฉํ์ง ๋ง์!! (์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ ์ฝ๋์ ๊ด๊ณ ์๋ ํ ์คํธ ์ฝ๋์์๋ ์ฌ์ฉ ๊ฐ๋ฅ)
4. ์คํ๋ง ์ค์ ์ ๋ชฉ์ ์ผ๋ก ํ๋ @Configuration ๊ฐ์ ๊ณณ์์๋ง ํน๋ณํ ์ฉ๋๋ก ์ฌ์ฉํฉ๋๋ค.
5. ์์กด ๊ด๊ณ๋ฅผ ํ๋์ ๋ฝ! ๋ฃ์ด์ฃผ๋ ๊ฒ์ ๋๋ค.
@Component
public class OrderServiceImpl implements OrderService {
//ํ๋ ์ฃผ์
๋ถ๋ถ
@Autowired
private MemberRepository memberRepository;
@Autowired
private DiscountPolicy discountPolicy;
}
๊ถ์ฅํ์ง ์์ต๋๋ค!!
์ฐธ๊ณ !! ์์ํ ์๋ฐ ํ ์คํธ ์ฝ๋์์๋ ๋น์ฐํ @Autowired๊ฐ ๋์ํ์ง ์์ต๋๋ค.
@SpringBootTest์ฒ๋ผ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํ ์คํธ์ ํตํฉํ ๊ฒฝ์ฐ์๋ง ๊ฐ๋ฅํฉ๋๋ค.
@Bean
OrderService orderService(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
return new OrderServiceImpl(memberRepository, discountPolicy);
}
์ฐธ๊ณ !! ์์ ์ฝ๋์ ๊ฐ์ด @Bean์์ ํ๋ผ๋ฏธํฐ์ ์์กด๊ด๊ณ๋ ์๋ ์ฃผ์ ๋ฉ๋๋ค.
์๋ ๋ฑ๋ก ์ ์๋ ๋ฑ๋ก ๋ ๋น์ ์์กด ๊ด๊ณ๊ฐ ํ์ํ ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.

1-4. ์ผ๋ฐ ๋ฉ์๋ ์ฃผ์
์ผ๋ฐ ๋ฉ์๋๋ฅผ ํตํด์ ์ฃผ์ ๋ฐ์ ์ ์์ต๋๋ค.
<ํน์ง>
1. ํ ๋ฒ์ ์ฌ๋ฌ ํ๋๋ฅผ ์ฃผ์ ๋ฐ์ ์ ์์ต๋๋ค. (์๋ฌด ๋ฉ์๋์ ๋๊ณ @Autowired๋ฅผ ์ธ ์ ์์)
2. ์ผ๋ฐ์ ์ผ๋ก ์ ์ฌ์ฉํ์ง๋ ์์ต๋๋ค. (์ฌ์ค ์ ๋งํ๋ฉด ์์ฑ์ ์ฃผ์ , ์์ ์ ์ฃผ์ ์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ)
@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;
}
}
์ฐธ๊ณ !! ์์กด ๊ด๊ณ ์๋ ์ฃผ์ ์ ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ด๋ฆฌํ๋ ์คํ๋ง ๋น์ด์ด์ผ ๋์ํฉ๋๋ค.
์คํ๋ง ๋น์ด ์๋ Member ๊ฐ์ ํด๋์ค์์ @Autowired ์ฝ๋๋ฅผ ์ ์ฉํด๋ ์๋ฌด ๊ธฐ๋ฅ๋ ๋์ํ์ง ์์ต๋๋ค.

2. ์ต์ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
์ฃผ์ ํ ์คํ๋ง ๋น์ด ์์ด๋ ๋์ํด์ผ ํ ๋๊ฐ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ, @Autowired๋ง ์ฌ์ฉํ๋ฉด, required ์ต์ ์ ๊ธฐ๋ณธ๊ฐ์ด true๋ก ๋์ด ์์ด์
์๋ ์ฃผ์ ๋์์ด ์์ผ๋ฉด ๋ฌด์กฐ๊ฑด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
<์๋ ์ฃผ์ ๋์์ ์ต์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ>
1. @Autowired(required = false): ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด, ์์ ์ ๋ฉ์๋ ์์ฒด๊ฐ ํธ์ถ์ด ์ ๋ฉ๋๋ค.
2. org.springframework.lang.@Nullable: ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด, null์ด ์ ๋ ฅ๋ฉ๋๋ค.
3. Optional<>: ์๋ ์ฃผ์ ํ ๋์์ด ์์ผ๋ฉด, Optional.empty๊ฐ ์ ๋ ฅ๋ฉ๋๋ค.
์์ ๋ก ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
test ํจํค์ง์ hello.core์ autowired๋ผ๋ ํจํค์ง๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ํจํค์ง ์์ AutowiredTest๋ผ๋ ์๋ฐ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
public class AutowiredTest {
@Test
void AutowiredOption() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestBean.class);
}
static class TestBean {
//1. ์๋ ์ฃผ์
ํ ๋์์ด ์์ผ๋ฉด, ์์ ์ ๋ฉ์๋ ์์ฒด๊ฐ ํธ์ถ์ด ์ ๋ฉ๋๋ค.
//๊ธฐ๋ณธ๊ฐ์ true
@Autowired(required = false)
public void setNoBean1(Member noBean1) {
System.out.println("noBean1 = " + noBean1);
}
//2. ์๋ ์ฃผ์
ํ ๋์์ด ์์ผ๋ฉด, null์ด ์
๋ ฅ๋ฉ๋๋ค.
@Autowired
public void setNoBean2(@Nullable Member noBean2) {
System.out.println("noBean2 = " + noBean2);
}
//3. ์๋ ์ฃผ์
ํ ๋์์ด ์์ผ๋ฉด, Optional.empty๊ฐ ์
๋ ฅ๋ฉ๋๋ค.
@Autowired
public void setNoBean3(Optional<Member> noBean3) {
System.out.println("noBean3 = " + noBean3);
}
}
}
์ด๋ ๊ฒ ํ ์คํธ ์ฝ๋๋ฅผ ์ง ๋ดค์ต๋๋ค.
์ฌ๊ธฐ์ Member๋ ์คํ๋ง ๋น์ด ์๋์ด์ ์๋ ์ฃผ์ ํ ๋์์ด ์๊ฒ ๋ฉ๋๋ค.
๊ฒฐ๊ณผ๋ ์ด๋ป๊ฒ ๋์ฌ๊น์?
์์๋๋ก 1๋ฒ์ ๊ฒฝ์ฐ๋ ์๋ ์ฃผ์ ํ ๋์์ด ์์ด์ ์์ ์ ๋ฉ์๋ ์์ฒด๊ฐ ํธ์ถ์ด ์ ๋์ด ๊ฒฐ๊ณผ๊ฐ ๋์ค์ง ์์์ต๋๋ค.
required = false๋ฅผ true๋ก ๋ฐ๊พธ๋ฉด ๋ฐ๋ก ์ค๋ฅ๊ฐ ๋ ๋ฒ๋ฆฝ๋๋ค.
2๋ฒ์ ๊ฒฝ์ฐ์ 3๋ฒ์ ๊ฒฝ์ฐ ๋ ๋ค ์์ํ ๋๋ก ์๋ ์ฃผ์ ํ ๋์์ด ์์ด์ ๊ฐ๊ฐ null๊ณผ Optional.empty๊ฐ ๋ด์ต๋๋ค.
์ฐธ๊ณ !! @Nullable, Optional์ ์คํ๋ง ์ ๋ฐ์ ๊ฑธ์ณ์ ์ง์๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด์, ์์ฑ์ ์๋ ์ฃผ์ ์์ ํน์ ํ๋์๋ง ์ฌ์ฉํด๋ ๋ฉ๋๋ค.

3. ์์ฑ์ ์ฃผ์ ์ ์ ํํด๋ผ!!
๊ณผ๊ฑฐ์๋ ์์ ์ ์ฃผ์ ๊ณผ ํ๋ ์ฃผ์ ์ ๋ง์ด ์ฌ์ฉํ์ง๋ง, ์ต๊ทผ์๋ ์คํ๋ง์ ํฌํจํ DI ํ๋ ์์ํฌ ๋๋ถ๋ถ์ด ์์ฑ์ ์ฃผ์ ์ ๊ถ์ฅํฉ๋๋ค.
์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
3-1. ์ด์ 1 - ๋ถ๋ณ
- ๋๋ถ๋ถ์ ์์กด ๊ด๊ณ ์ฃผ์
์ ํ ๋ฒ ์ผ์ด๋๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์ข
๋ฃ ์์ ๊น์ง ์์กด ๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ ์ผ์ด ์์ต๋๋ค.
- ์คํ๋ ค ๋๋ถ๋ถ์ ์์กด ๊ด๊ณ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ข ๋ฃ ์ ๊น์ง ๋ณํ๋ฉด ์ ๋ฉ๋๋ค. (๋ถ๋ณํด์ผ ํฉ๋๋ค.)
- ์์ ์ ์ฃผ์
์ ์ฌ์ฉํ๋ฉด, setXxx ๋ฉ์๋๋ฅผ public์ผ๋ก ์ด์ด๋์ด์ผ ํฉ๋๋ค.
- ๋๊ตฐ๊ฐ๊ฐ ์ค์๋ก ๋ณ๊ฒฝํ ์๋ ์๊ณ , ๋ณ๊ฒฝํ๋ฉด ์ ๋๋ ๋ฉ์๋๋ฅผ ์ด์ด๋๋ ๊ฒ์ ์ข์ ์ค๊ณ ๋ฐฉ๋ฒ์ด ์๋๋๋ค.
- ์์ฑ์ ์ฃผ์
์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ๋ฑ 1๋ฒ๋ง ํธ์ถ๋๋ฏ๋ก ์ดํ์ ํธ์ถ๋๋ ์ผ์ด ์์ต๋๋ค.
- ๋ฐ๋ผ์, ๋ถ๋ณํ๊ฒ ์ค๊ณํ ์ ์์ต๋๋ค.
3-2. ์ด์ 2 - ๋๋ฝ
ํ๋ ์์ํฌ ์์ด ์์ํ ์๋ฐ ์ฝ๋๋ฅผ ๋จ์ ํ ์คํธ ํ๋ ๊ฒฝ์ฐ์... (๋ฑ OrderServiceImpl๋ง ํ ์คํธ๋ฅผ ํ๊ณ ์ถ๋ค!)
๋ค์๊ณผ ๊ฐ์ด ์์ ์ ์์กด ๊ด๊ณ์ธ ๊ฒฝ์ฐ
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๊ฐ ํ๋ ์์ํฌ ์์์ ๋์ํ ๋๋ ์์กด ๊ด๊ณ๊ฐ ์์ผ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง๋ง, ์ง๊ธ์ ํ๋ ์์ํฌ ์์ด ์์ํ ์๋ฐ ์ฝ๋๋ก๋ง ๋จ์ ํ ์คํธ๋ฅผ ์ํํ๊ณ ์์ต๋๋ค.
์ด๋ ๊ฒ ํ ์คํธ๋ฅผ ์ํํ๋ฉด ์คํ์ ๋ฉ๋๋ค.
@Test
void createOrder() {
OrderServiceImpl orderService = new OrderServiceImpl();
orderService.createOrder(1L, "itemA", 10000);
}
๊ทธ๋ฐ๋ฐ ๋ง์ ์คํ ๊ฒฐ๊ณผ๋ NPE(Null Point Exception)์ด ๋ฐ์ํ๋๋ฐ, memberRepository์ discountPolicy ๋ชจ๋ ์์กด ๊ด๊ณ ์ฃผ์ ์ด ๋๋ฝ๋์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด ๋ค์์ฒ๋ผ ์ฃผ์ ๋ฐ์ดํฐ๋ฅผ ๋๋ฝํ์ ๋ ์ปดํ์ผ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , IDE์์ ๋ฐ๋ก ์ด๋ค ๊ฐ์ ํ์๋ก ์ฃผ์ ํด์ผ ํ๋์ง ์ ์ ์์ต๋๋ค.
3-3. ์ด์ 3 - final ํค์๋
์์ฑ์ ์ฃผ์ ์ ์คํํ๋ฉด ํ๋์ 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;
}
...
}
์ ๋ณด๋ฉด ํ์ ํ๋์ธ discountPolicy์ ๊ฐ์ ์ค์ ํด์ผ ํ๋๋ฐ, ์ด ๋ถ๋ถ์ด ๋๋ฝ๋์์ต๋๋ค.
์๋ฐ๋ ์ปดํ์ผ ์์ ์ java: variable discountPolicy might not have been initialized ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค.
์ปดํ์ผ ์ค๋ฅ๋ ์ธ์์์ ๊ฐ์ฅ ๋น ๋ฅด๊ณ ์ข์ ์ค๋ฅ ์ ๋๋ค!!!!
์ฐธ๊ณ !! ์์ ์ ์ฃผ์ ์ ํฌํจํ ๋๋จธ์ง ์ฃผ์ ๋ฐฉ์์ ๋ชจ๋ ์์ฑ์ ์ดํ์ ํธ์ถ๋๋ฏ๋ก, ํ๋์ final ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ค์ง ์์ฑ์ ์ฃผ์ ๋ฐฉ์๋ง final ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.โญ
<์ ๋ฆฌโ๏ธ>
- ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ ์ ํํ๋ ์ด์ ๋ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ง๋ง, ํ๋ ์์ํฌ์ ์์กดํ์ง ์๊ณ ์์ํ ์๋ฐ ์ธ์ด์ ํน์ง์ ์ ์ด๋ฆฌ ๋ ๋ฐฉ๋ฒ์ด๊ธฐ๋ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
- ๊ธฐ๋ณธ์ผ๋ก ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ๊ณ , ํ์ ๊ฐ์ด ์๋ ๊ฒฝ์ฐ์๋ ์์ ์ ์ฃผ์ ๋ฐฉ์์ ์ต์ ์ผ๋ก ๋ถ์ฌํ๋ฉด ๋ฉ๋๋ค.
(์์ฑ์ ์ฃผ์ ๊ณผ ์์ ์ ์ฃผ์ ์ ๋์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.)
- ํญ์ ์์ฑ์ ์ฃผ์ ์ ์ ํํด์ผ ํ๊ณ , ๊ฐ๋ ์ต์ ์ด ํ์ํ๋ฉด ์์ ์ ์ฃผ์ ์ ์ ํํด์ผ ํฉ๋๋ค.
ํ๋ ์ฃผ์ ์ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค!!

4. ๋กฌ๋ณต(Lombok)๊ณผ ์ต์ ํธ๋๋
๋ง์ ๊ฐ๋ฐ์ ํด๋ณด๋ฉด ๋๋ถ๋ถ์ด ๋ค ๋ถ๋ณ์ ๋๋ค.
๊ทธ๋์ ํ๋์ final ํค์๋๋ฅผ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค.
๊ทธ๋ฐ๋ฐ, ์์ฑ์๋ ๋ง๋ค์ด์ผ ํ๊ณ .. ์ฃผ์ ๋ฐ์ ๊ฐ์ ๋์ ํ๋ ์ฝ๋๋ ๋ง๋ค์ด์ผ ํ๊ณ ...
ํ๋ ์ฃผ์ ์ฒ๋ผ ์ข ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๊น์?
4-1. ๊ธฐ๋ณธ ์ฝ๋ ์ต์ ํ
<๊ธฐ๋ณธ ์ฝ๋>
@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 final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
4-2. ๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฉ ๋ฐฉ๋ฒ
์ด์ ๋กฌ๋ณต์ ์ ์ฉํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๊ณตํ๋ @RequiredArgsConstructor ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด final์ด ๋ถ์ ํ๋๋ฅผ ๋ชจ์์ ์์ฑ์๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ด์ค๋๋ค. (๋ค์ ์ฝ๋์๋ ๋ณด์ด์ง ์์ง๋ง ์ค์ ํธ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค.)
์์ฆ ๋กฌ๋ณต ์ธ๊ธฐ ๋ง์์ spring initializr์์ Dependencies์ Lombok ๋ฐ๋ก ์ถ๊ฐํ๋ฉด ์๋์ผ๋ก ๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
์ฒ์์ ๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ์ฉํ์ง ์๊ณ ํ๋ก์ ํธ๋ฅผ ์์ฑํ์ผ๋ฉด ๋ฐ์ ๋ฐฉ๋ฒ๋๋ก ํ๋ฉด ๋ฉ๋๋ค.
<build.gradle์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ํ๊ฒฝ ์ถ๊ฐ>
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.4'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'hello'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
//Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ ์์
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
//Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ๊ฐ ๋
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
์์ ์ฝ๋์ฒ๋ผ ๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๊ณ , ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ํ๋ฉด ๋ฉ๋๋ค.
1. Preferences(์๋์ฐ File๐๐ปSettings)๐๐ปplugin๐๐ปlombok ๊ฒ์ ์ค์น ์คํ (์ฌ์์)
2. Preferences๐๐ปAnnotation Processors ๊ฒ์๐๐ปEnable annotation processing ์ฒดํฌ (์ฌ์์)
3. ์์์ ํ ์คํธ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , @Getter์ @Setter ํ์ธ
์ ๋์๋์ง ํ์ธํด๋ณด๊ธฐ ์ํด์ ์์์ ํ ์คํธ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
src.main.java.hello.core์ HelloLombok์ด๋ผ๋ ์๋ฐ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
package hello.core;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class HelloLombok {
private String name;
private int age;
public static void main(String[] args) {
HelloLombok helloLombok = new HelloLombok();
helloLombok.setName("์ด๋ฆฌ์ญ");
System.out.println("helloLombok = " + helloLombok);
}
}
4-3. ๋กฌ๋ณต ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ์ฉ ํ
์ต์ข ๊ฒฐ๊ณผ ์ฝ๋๋ฅผ ๋ณด๋ฉด ์ ๋ง ๊ฐ๊ฒฐํ๋ค๋ ๊ฒ์ ๋๋ ์ ์์ต๋๋ค.
<์ต์ข ๊ฒฐ๊ณผ ์ฝ๋>
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
์ด ์ต์ข ๊ฒฐ๊ณผ ์ฝ๋์ ์ด์ ์ ์ฝ๋๋ ์์ ํ ๋์ผํฉ๋๋ค.
๋กฌ๋ณต์ด ์๋ฐ์ ์ ๋ ธํ ์ด์ ํ๋ก์ธ์๋ผ๋ ๊ธฐ๋ฅ์ ์ด์ฉํด์ ์ปดํ์ผ ์์ ์ ์์ฑ์ ์ฝ๋๋ฅผ ์๋์ผ๋ก ์์ฑํด์ค๋๋ค.
์ค์ class๋ฅผ ์ด์ด๋ณด๋ฉด ๋ฐ์ ์ฝ๋๊ฐ ์ถ๊ฐ๋์ด ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
<์ ๋ฆฌโ๏ธ>
์ต๊ทผ์๋ ์์ฑ์๋ฅผ ๋ฑ 1๊ฐ ๋๊ณ , @Autowired๋ฅผ ์๋ตํ๋ ๋ฐฉ๋ฒ์ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค.
์ฌ๊ธฐ์ Lombok ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ @RequiredArgsConstructor๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ๊ธฐ๋ฅ์ ๋ค ์ ๊ณตํ๋ฉด์, ์ฝ๋๋ ๊น๋ํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.

5. ์กฐํ ๋น์ด 2๊ฐ ์ด์ - ๋ฌธ์
@Autowired๋ ํ์ (Type)์ผ๋ก ์กฐํํฉ๋๋ค.
@Autowired
private DiscountPolicy discountPolicy
ํ์ ์ผ๋ก ์กฐํํ๊ธฐ ๋๋ฌธ์, ๋ง์น ac.getBean(DiscountPolicy.class)์ ์ ์ฌํ๊ฒ ๋์ํฉ๋๋ค.
=> ์ค์ ๋ก๋ ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์คํ๋ง ๋น ์กฐํ์์ ๋ดค๋ฏ์ด, ํ์ ์ผ๋ก ์กฐํํ๋ฉด ์ ํ๋ ๋น์ด 2๊ฐ ์ด์์ผ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
DiscountPolicy์ ํ์ ํ์ ์ธ FixDiscountPolicy, RateDiscountPolicy ๋ ๋ค ์คํ๋ง ๋น์ผ๋ก ์ ์ธํด๋ณด๊ฒ ์ต๋๋ค.
<FixDiscountPolicy>
@Component
public class FixDiscountPolicy implements DiscountPolicy { }
<RateDiscountPolicy>
@Component
public class RateDiscountPolicy implements DiscountPolicy { }
๊ทธ๋ฆฌ๊ณ , ์ด๋ ๊ฒ ์์กด ๊ด๊ณ ์๋ ์ฃผ์ ์ ์คํํ๋ฉด
@Autowired
private DiscountPolicy discountPolicy
๋ฐ์์ฒ๋ผ NoUniqueBeanDefinitionException ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
NoUniqueBeanDefinitionException: No qualifying bean of type
'hellp.core.discount.DiscountPolicy' avaliable: expected single matching bean
but found 2: fixDiscountPolicy, rateDiscountPolicy
์ค๋ฅ ๋ฉ์์ง๊ฐ ์น์ ํ๊ฒ๋ ํ๋์ ๋น์ ๊ธฐ๋ํ๋๋ฐ fixDiscountPolicy, rateDiscountPolicy 2๊ฐ๊ฐ ๋ฐ๊ฒฌ๋์๋ค๊ณ ์๋ ค์ค๋๋ค.
์ด ๋, ํ์ ํ์ ์ผ๋ก ์ง์ ํ ์๋ ์์ง๋ง, ํ์ ํ์ ์ผ๋ก ์ง์ ํ๋ ๊ฒ์ DIP๋ฅผ ์๋ฐํ๊ณ ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋๋ค.
๊ทธ๋ฆฌ๊ณ , ์ด๋ฆ๋ง ๋ค๋ฅด๊ณ ์์ ํ ๋๊ฐ์ ํ์ ์ ์คํ๋ง ๋น์ด 2๊ฐ ์์ ๋ ํด๊ฒฐ์ด ์ ๋ฉ๋๋ค.
์คํ๋ง ๋น์ ์๋ ๋ฑ๋กํด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋ ๋์ง๋ง,
์์กด ๊ด๊ณ ์๋ ์ฃผ์ ์์ ์กฐํ ๋์ ๋น์ด 2๊ฐ ์ด์์ผ ๋ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- @Autowired ํ๋ ๋ช ๋งค์นญ
- @Qualifier๐๐ป@Qualifier๋ผ๋ฆฌ ๋งค์นญ๐๐ป๋น ์ด๋ฆ ๋งค์นญ
- @Primary ์ฌ์ฉ
5-1. ํด๊ฒฐ ๋ฐฉ๋ฒ1 - @Autowired ํ๋ ๋ช ๋งค์นญ
@Autowired๋ ํ์ ๋งค์นญ์ ์๋ํ๋๋ฐ ์ด ๋ ์ฌ๋ฌ ๋น์ด ์์ผ๋ฉด ํ๋ ์ด๋ฆ, ํ๋ผ๋ฏธํฐ ์ด๋ฆ์ผ๋ก ๋น ์ด๋ฆ์ ์ถ๊ฐ ๋งค์นญํฉ๋๋ค.
<๊ธฐ์กด ์ฝ๋>
@Autowired
private DiscountPolicy discountPolicy
<ํ๋ ๋ช ์ ๋น ์ด๋ฆ์ผ๋ก ๋ณ๊ฒฝ>
@Autowired
private DiscountPolicy rateDiscountPolicy
ํ๋ ๋ช ์ด rateDiscountPolicy์ด๋ฏ๋ก ์ ์ ์ฃผ์ ๋ฉ๋๋ค.
ํ๋ ๋ช ๋งค์นญ์ ๋จผ์ ํ์ ๋งค์นญ์ ์๋ํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ์ ์ฌ๋ฌ ๋น์ด ์์ ๋ ์ถ๊ฐ๋ก ๋์ํ๋ ๊ธฐ๋ฅ์ ๋๋ค.
<์ ๋ฆฌโ๏ธ>
1. ํ์ ๋งค์นญ
2. ํ์ ๋งค์นญ์ ๊ฒฐ๊ณผ๊ฐ 2๊ฐ ์ด์์ผ ๋ ํ๋ ๋ช , ํ๋ผ๋ฏธํฐ ๋ช ์ผ๋ก ๋น ์ด๋ฆ ๋งค์นญ
5-2. ํด๊ฒฐ ๋ฐฉ๋ฒ2 - @Qualifier ์ฌ์ฉ
@Qualifier๋ ์ถ๊ฐ ๊ตฌ๋ถ์๋ฅผ ๋ถ์ฌ์ฃผ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
์ฃผ์ ์ ์ถ๊ฐ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๊ฒ์ด๊ณ , ๋น ์ด๋ฆ์ ๋ณ๊ฒฝํ๋ ๊ฒ์ ์๋๋๋ค.
<๋น ๋ฑ๋ก ์ @Qualifier๋ฅผ ๋ถ์ฌ์ค๋๋ค.>
@Component
@Qualifier("mainDiscountPolicy")
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
@Qualifier("fixDiscountPolicy")
public class FixDiscountPolicy implements DiscountPolicy {}
์ฃผ์ ์์ @Qualifier๋ฅผ ๋ถ์ฌ์ฃผ๊ณ ๋ฑ๋กํ ์ด๋ฆ์ ์ ์ด์ค๋๋ค.
<์์ฑ์ ์๋ ์ฃผ์ ์์>
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
<์์ ์ ์๋ ์ฃผ์ ์์>
@Autowired
public DiscountPolicy setDiscountPolicy(@Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
@Qualifier๋ก ์ฃผ์ ํ ๋ @Qualifier("mainDiscountPolicy")๋ฅผ ๋ชป ์ฐพ์ผ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์?
๊ทธ๋ฌ๋ฉด mainDiscountPolicy๋ผ๋ ์ด๋ฆ์ ์คํ๋ง ๋น์ ์ถ๊ฐ๋ก ์ฐพ์ต๋๋ค.
ํ์ง๋ง, @Qualifier๋ @Qualifier๋ฅผ ์ฐพ๋ ์ฉ๋๋ก๋ง ์ฌ์ฉํ๋ ๊ฒ์ด ๋ช ํํ๊ณ ์ข์ต๋๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ง์ ๋น ๋ฑ๋ก ์์๋ @Qualifier๋ฅผ ๋์ผํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@Bean
@Qualifier("mainDiscountPolicy")
public DiscountPolicy discountPolicy() {
return new ...
}
<์ ๋ฆฌโ๏ธ>
1. @Qualifier๋ผ๋ฆฌ ๋งค์นญ
2. ๋น ์ด๋ฆ ๋งค์นญ
3. NoSuchBeanDefinitionException ์์ธ ๋ฐ์
5-3. ํด๊ฒฐ ๋ฐฉ๋ฒ3 - @Primary ์ฌ์ฉ
@Primary๋ ์ฐ์ ์์๋ฅผ ์ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. (ํธ๋ฆฌํ๊ณ , ์์ฃผ ์ฌ์ฉ)
@Autowired ์์ ์ฌ๋ฌ ๋น์ด ๋งค์นญ๋๋ฉด @Primary๊ฐ ์ฐ์ ๊ถ์ ๊ฐ์ง๋๋ค.
<rateDiscountPolicy๊ฐ ์ฐ์ ๊ถ์ ๊ฐ์ง๋๋ก ํ์>
@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}
@Component
public class FixDiscountPolicy implements DiscountPolicy {}
<์ฌ์ฉ ์ฝ๋>
//์์ฑ์
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
//์์ ์
@Autowired
public DiscountPolicy setDiscountPolicy(DiscountPolicy discountPolicy) {
this.discountPolicy = discountPolicy;
}
์ฝ๋๋ฅผ ์คํํด๋ณด๋ฉด ๋ฌธ์ ์์ด @Primary๊ฐ ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
์ฌ๊ธฐ๊น์ง ๋ณด๋ฉด @Primary์ @Qualifier ์ค์ ์ด๋ค ๊ฒ์ ์ฌ์ฉํ๋ฉด ์ข์์ง ๊ณ ๋ฏผํ ์๊ฐ ์์ต๋๋ค.
@Qualifier์ ๋จ์ ์ ์ฃผ์ ๋ฐ์ ๋ ๋ชจ๋ ์ฝ๋์ @Qualifier๋ฅผ ๋ถ์ฌ์ฃผ์ด์ผ ํ๋ค๋ ์ ์ ๋๋ค.
@Autowired
public OrderServiceImpl(MemberRepository memberRepository, @Qualifier("mainDiscountPolicy") DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
<๐ป์ฐธ๊ณ - @Primary, @Qualifier ํ์ฉ๐ป>
์ฝ๋์์ ์์ฃผ ์ฌ์ฉํ๋ ๋ฉ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ปค๋ฅ์ ์ ํ๋ํ๋ ์คํ๋ง ๋น์ด ์๊ณ , ์ฝ๋์์ ํน๋ณํ ๊ธฐ๋ฅ์ผ๋ก ๊ฐ๋ ์ฌ์ฉํ๋ ์๋ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ปค๋ฅ์ ์ ํ๋ํ๋ ์คํ๋ง ๋น์ด ์๋ค๊ณ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๋ฉ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ปค๋ฅ์ ์ ํ๋ํ๋ ์คํ๋ง ๋น์ @Primary๋ฅผ ์ ์ฉํ๊ณ ์กฐํํ๋ ๊ณณ์์ @Qualifier ์ง์ ์์ด ํธ๋ฆฌํ๊ฒ ์กฐํํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , ์๋ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ๋น์ ํ๋ํ ๋๋ @Qualifier๋ฅผ ์ง์ ํด์ ๋ช ์์ ์ผ๋ก ํ๋ํ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
์๋ ๊ฒ ํ๋ฉด ์ฝ๋๋ฅผ ๊น๋ํ๊ฒ ์ ์งํ ์ ์์ต๋๋ค.
๋ชฐ๋ก ์ด ๋ ๋ฉ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋ @Qualifier๋ฅผ ์ง์ ํด์ฃผ๋ ๊ฒ์ ์๊ด ์์ต๋๋ค.
<์ฐ์ ์์โญ>
@Primary๋ ๊ธฐ๋ณธ๊ฐ์ฒ๋ผ ๋์ํ๋ ๊ฒ์ด๊ณ , @Qualifier๋ ๋งค์ฐ ์์ธํ๊ฒ ๋์ํ๋ ๊ฒ์ ๋๋ค.
์ด๋ฐ ๊ฒฝ์ฐ ์ด๋ค ๊ฒ์ด ์ฐ์ ๊ถ์ ๊ฐ์ ธ๊ฐ๊น์?
์คํ๋ง์์๋ ์์ธํ ๊ฒ์ด ์ฐ์ ๊ถ์ ๊ฐ์ ธ๊ฐ๋๋ค.
์๋๋ณด๋ค๋ ์๋์ด, ๋์ ๋ฒ์์ ์ ํ๊ถ๋ณด๋ค๋ ์ข์ ๋ฒ์์ ์ ํ๊ถ์ด ์ฐ์ ์์๊ฐ ๋์ต๋๋ค.
๋ฐ๋ผ์, ์ฌ๊ธฐ์๋ @Qualifier๊ฐ ์ฐ์ ๊ถ์ด ๋์ต๋๋ค.
5-4. ์ ๋ ธํ ์ด์ ์ง์ ๋ง๋ค๊ธฐ
@Qualifier("mainDiscountPolicy") ์ด๋ ๊ฒ ๋ฌธ์๋ฅผ ์ ์ผ๋ฉด ์ปดํ์ผ ์ ํ์ ์ฒดํฌ๊ฐ ์ ๋ฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ ์ ๋ ธํ ์ด์ ์ ๋ง๋ค์ด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
main์ hello.core์ annotation์ด๋ผ๋ ํจํค์ง๋ฅผ ๋ง๋ญ๋๋ค.
์ด ํจํค์ง ์์ MainDiscountPolicy๋ผ๋ ์ ๋ ธํ ์ด์ ์ ๋ง๋ญ๋๋ค.
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier("mainDiscountPolicy")
public @interface MainDiscountPolicy {
}
์ด ์ ๋ ธํ ์ด์ ์ @Qualifier("mainDiscountPolicy")๋ฅผ ์ ์ด์ค๋๋ค.
@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy{
private int discountPercent = 10; //10% ํ ์ธ
@Override
public int discount(Member member, int price) {
if(member.getGrade() == Grade.VIP) {
return price * discountPercent /100;
}
else {
return 0;
}
}
}
๊ทธ๋ฆฌ๊ณ , ์์์ ์ ์๋ mainDiscountPolicy๋ฅผ ์ฌ๊ธฐ์ @MainDiscountPolicy๋ก ์ ์ด์ค๋๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์ฅ์ ์ด ์์ต๋๋ค.
๊ธฐ์กด์ @Qualify("mainDiscountPolicy")๋ ๊ดํธ ์์ ์๋ ๊ฒ์ ๋ฌธ์๋ก ์ธ์ํด์ ์ฒ ์๊ฐ ํ๋ฆฌ๊ฑฐ๋ ํ๋ฉด ์ค๋ฅ๋ฅผ ์ก์๋ด์ง ๋ชปํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ๋ฐ๊พธ๋ฉด์ ์ฒ ์๊ฐ ํ๋ ค๋ ์ค๋ฅ๋ฅผ ์ก์๋ผ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ๋ ธํ ์ด์ ์๋ ์์์ด๋ผ๋ ๊ฐ๋ ์ด ์์ต๋๋ค.
์ด๋ ๊ฒ ์ฌ๋ฌ ์ ๋ ธํ ์ด์ ์ ๋ชจ์์ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ ์คํ๋ง์ด ์ง์ํด์ฃผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
@Qualifier ๋ฟ๋ง ์๋๋ผ ๋ค๋ฅธ ์ ๋ ธํ ์ด์ ๋ค๋ ํจ๊ป ์กฐํฉํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ์ ์ผ๋ก @Autowired๋ ์ฌ์ ์ ํ ์ ์์ต๋๋ค.
๋ชฐ๋ก ์คํ๋ง์ด ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ ๋๋ ทํ ๋ชฉ์ ์์ด ๋ฌด๋ถ๋ณํ๊ฒ ์ฌ์ ์ํ๋ ๊ฒ์ ์ ์ง๋ณด์์ ๋ ํผ๋๋ง ๊ฐ์คํ ์ ์์ต๋๋ค.

6. ์กฐํํ ๋น์ด ๋ชจ๋ ํ์ํ ๋: List, Map
์๋์ ์ผ๋ก ์ ๋ง ํด๋น ํ์ ์ ์คํ๋ง ๋น์ด ๋ค ํ์ํ ๊ฒฝ์ฐ๋ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด์ ํ ์ธ ์๋น์ค๋ฅผ ์ ๊ณตํ๋๋ฐ, ํด๋ผ์ด์ธํธ๊ฐ ํ ์ธ์ ์ข ๋ฅ(rate, fix)๋ฅผ ์ ํํ ์ ์๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค.
์คํ๋ง์ ์ฌ์ฉํ๋ฉด ์์ ๋งํ๋ ์ ๋ต ํจํด์ ๋งค์ฐ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
Test ํจํค์ง์์ autowired ํจํค์ง ์์ AllBeanTest๋ผ๋ ์๋ฐ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
public class AllBeanTest {
@Test
void findAllBean() {
ApplicationContext ac = new AnnotationConfigApplicationContext(DiscountService.class);
}
static class DiscountService {
private final Map<String, DiscountPolicy> policyMap;
private final List<DiscountPolicy> policies;
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);
}
}
}
์กฐํํ ๋น์ด ๋ชจ๋ ํ์ํ๊ธฐ์ Map๊ณผ List๋ฅผ ์ฌ์ฉํ์์ต๋๋ค.
์๋ ์์กด๊ด๊ณ ์ฃผ์ ์ด ๋๊ธฐ ์ ์ ๋๋ค. ๊ฒฐ๊ณผ๊ฐ ๊ณผ์ฐ ์ด๋ป๊ฒ ๋์ฌ๊น์?
์ด๋ ๊ฒ ์๋ฌด ๊ฐ๋ ์ ๋์ต๋๋ค.
์ด๋ฒ์ ์๋ ์์กด๊ด๊ณ ์ฃผ์ ์ ํด๋ณผ๊ฒ์.
public class AllBeanTest {
@Test
void findAllBean() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
}
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);
}
}
}
AutoAppConfig.class์ @Autowired๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
๊ทธ๋ผ ๊ฒฐ๊ณผ๋ฅผ ํ ๋ฒ ๋ด๋ณด๊ฒ ์ต๋๋ค.
๊ฐ์ด ์ ๋์ต๋๋ค.
List๋ Value๋ง ์๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ด ์๊ณ , Map์ <Key, Value> ๋ ๋ค ์๊ธฐ ๋๋ฌธ์ ์ด๋ฆ์ด ์์ต๋๋ค.
๋น์ฆ๋์ค ๋ก์ง์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
@Test
void findAllBean() {
ApplicationContext 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);
}
VIP ๋ฑ๊ธ์ธ userA๋ผ๋ ์ฌ๋๊ณผ ๊ทธ ์ฌ๋์ด 10000์์ง๋ฆฌ ๋ฌผ๊ฑด์ ์์ ๋์ ํ ์ธ ๊ธ์ก์ ์ฝ๋๋ฅผ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ํด๋์ผ๋ฉด discount์ ๋นจ๊ฐ์์ด ๋ฐ ๊ฒ์ ๋๋ค.
discount์ create Method๋ฅผ ํ๋ฉด
public int discount(Member member, int i, String fixDiscountPolicy) {
return 0;
}
์ด ์ฝ๋๊ฐ ์๊ธธ ๊ฒ์ ๋๋ค.
์ด๋ฒ ์น์ ๋ ์ด๋ ๊ฒ ๋์ด ๋ฌ์ต๋๋ค.
ํ.. ์์ฒญ ๊ธธ์๋ค์ฅ..!!
๋ค์ ์น์ ์ ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ์ ๊ด๋ จํด์ ํ ์์ ์ ๋๋ค.
๊ทธ๋ผ ์๋ฝ!!
