/* ์ด ๊ธ์ ๊น์ํ๋์ ๊ฐ์๋ฅผ ๋ณด๊ณ ์ ๋ฆฌํ๋ ค๊ณ ์์ฑํ ๊ธ์ ๋๋ค.
๊ฐ์ธ์ ์ธ ๊ณต๋ถ๋ฅผ ์ํด ์ฌ๋ฆฌ๋ ๊ธ์ด๋ฏ๋ก ์ค๊ฐ ์ค๊ฐ ์ฝ๋๋ ์๋ต๋์์ต๋๋ค. */
@Configration๊ณผ ์ฑ๊ธํค
AppConfig
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
โ @Bean memberService โ new MemoryMemberRepository()
โ @Bean orderService โ new MemoryMemberRepository(), new RateDiscountPolicy()
โ ์ ์ฝ๋๋ฅผ ๋ณด๋ฉด ๊ฐ๊ฐ ๋ค๋ฅธ 2๊ฐ์ MemoryMemberRepository๊ฐ ์์ฑ๋๋ฉด์ ์ฑ๊ธํค์ด ๊นจ์ง๋ ๊ฒ ์ฒ๋ผ ๋ณด์ธ๋ค.
โ ์คํ๋ง ์ปจํ ์ด๋๋ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ๊น?
MemberServiceImpl, OrderServiceImpl
//ํ
์คํธ ์ฉ ์ฝ๋ ์ถ๊ฐ
public MemberRepository getMemberRepository() {
return memberRepository;
}
โ MemberServiceImpl, OrderServiceImpl์ ๊ฐ๊ฐ ํ ์คํธ ์ฝ๋ ์ถ๊ฐ
ConfigurationSingletonTest
public class ConfigurationSingletonTest {
@Test
void configurationTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);
MemberRepository memberRepository1 = memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
System.out.println("memberService -> memberRepository1 = " + memberRepository1);
System.out.println("orderService -> memberRepository2 = " + memberRepository2);
System.out.println("memberRepository = " + memberRepository);
Assertions.assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
Assertions.assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
โ ์ฝ์์ฐฝ์ ํ์ธํด๋ณด๋ฉด memberRepository ์ธ์คํด์ค๋ ๋ชจ๋ ๊ฐ์ ์ธ์คํด์ค๊ฐ ๊ณต์ ๋์ด ์ฌ์ฉ๋๋ค.
โ AppConfig์ ์๋ฐ ์ฝ๋๋ฅผ ๋ณด๋ฉด `new MemoryMemberRepository` ํธ์ถํด์ ๋ค๋ฅธ ์ธ์คํด์ค๊ฐ ์์ฑ๋์ด์ผ ํ๋๋ฐ ์ด๋ป๊ฒ ๋ ์ผ์ผ๊น?
AppConfig
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
System.out.println("Call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
System.out.println("Call AppConfig.orderService");
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
System.out.println("Call AppConfig.memberRepository");
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
System.out.println("Call AppConfig.discountPolicy");
return new RateDiscountPolicy();
}
}
โ ๋ก๊ทธ๋ฅผ ๋จ๊ธฐ๊ณ ํ ์คํธ๋ฅผ ์คํํ๋ฉด ๊ฐ๊ฐ ํ ๋ฒ๋ง ํธ์ถํ๋ ๊ฑธ ๋ณผ ์ ์๋ค.
โ ์ด๋ ํ ๋ฐฉ๋ฒ์ ์จ์๋ผ๋ ์คํ๋ง์ด ์ฑ๊ธํค์ ๋ณด์ฅํด์ฃผ๋ ๊ฑธ ์ ์ ์์. ์ด๋ ํ ๋ฐฉ๋ฒ์ธ์ง ๋ค์ ๊ฐ์์!
๐ก TIP
: sout ์ข ๋ฅ
โพ sout : `System.out.printil()` ์์ฑ
โพ soutv : ๋ณ์ ์ถ๋ ฅ
void configurationTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
System.out.println("memberService = " + memberService);
}
โพ soutp : ๋งค๊ฐ๋ณ์ ๊ฐ ์ถ๋ ฅ
public void join(Member member) {
memberRepository.save(member);
System.out.println("member = " + member);
}
โพ soutm : ํ์ฌ ํด๋์ค์ ๋ฉ์๋ ์ถ๋ ฅ
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
System.out.println("Call AppConfig.memberService");
return new MemberServiceImpl(memberRepository());
}
}
@Configration ๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์์ ๋ง๋ฒ
ConfigurationSingletonTest
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
โ AnnotationConfigApplicationContext์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธด ๊ฐ์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก์ด ๋๋ค.
โ AppConfig๋ ์คํ๋ง ๋น์ด ๋๋ฏ๋ก ๋ฑ๋กํ๊ณ ํด๋์ค ์ ๋ณด๋ฅผ ์ถ๋ ฅํด๋ณด์.
โ ์์ํ ์๋ฐ ํด๋์ค๋ผ๋ฉด `class.hello.core.AppConfig ` ๋ก ์ถ๋ ฅ๋์ด์ผ ํ๋๋ฐ ๋ค์ CGLIB๊ฐ ๋ถ์ผ๋ฉด์ ๋ณต์กํด์ง ๊ฒ์ ๋ณผ ์ ์๋ค.
โ ์คํ๋ง์ด CGLIB๋ผ๋ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ AppConfig ํด๋์ค๋ฅผ ์์๋ฐ์ ์์์ ๋ค๋ฅธ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ๊ทธ ๋ค๋ฅธ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
โ ์์์ ๋ค๋ฅธ ํด๋์ค๊ฐ ๋ฐ๋ก ์ฑ๊ธํค์ด ๋ณด์ฅ๋๋๋ก ํด์ค๋ค.
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository๊ฐ ์ด๋ฏธ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก๋์ด ์์ผ๋ฉด?) {
return ์คํ๋ง ์ปจํ
์ด๋์์ ์ฐพ์์ ๋ฐํ;
} else { //์คํ๋ง ์ปจํ
์ด๋์ ์์ผ๋ฉด
๊ธฐ์กด ๋ก์ง์ ํธ์ถํด์ MemoryMemberRepository๋ฅผ ์์ฑํ๊ณ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก
return ๋ฐํ
}
}
โ ์ค์ ๋ก CGLIB ๋ด๋ถ ๊ธฐ์ ์ ๊ต์ฅํ ๋ณต์กํ๋, ๊ฐ๋จํ ์ ์ผ๋ฉด ์์ฒ๋ผ ๋์ด์์ ๊ฒ์ด๋ผ๊ณ ํจ.
โ @Bean์ด ๋ถ์ ๋ฉ์๋๋ง๋ค ์ด๋ฏธ ์คํ๋ง ๋น์ด ์กด์ฌํ๋ฉด ์กด์ฌํ๋ ๋น์ ๋ฐํํ๊ณ , ์คํ๋ง ๋น์ด ์์ผ๋ฉด ์คํ๋ง ๋น์ผ๋ก ์์ฑํด์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๊ณ ๋ฐํํ๋ ์ฝ๋๊ฐ ๋์ ์ผ๋ก ๋ง๋ค์ด์ง๋ค.
๋ง์ฝ @Configuration์ ๋ถ์ด์ง ์๊ณ @Bean๋ง ์ ์ฉํ๋ค๋ฉด?
โพ AppConfig์์ @Configuration์ ์ง์ฐ๊ณ configurationDeep() ํ ์คํธ
โ MemberRepository๋ ์ด 3๋ฒ ํธ์ถ๋๋ค.
- 1. @Bean์ ์ํด ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋๊ธฐ ์ํด
- 2. memberService์์ memberRepository()๋ฅผ ํธ์ถํด์
- 3. orderService์์ memberRepository()๋ฅผ ํธ์ถํด์
โ AppConfig๊ฐ CGLIB ๊ธฐ์ ์์ด ์์ํ AppConfig๋ก ์คํ๋ง ๋น์ ๋ฑ๋ก๋๋ค.
โพ AppConfig์์ @Configuration์ ์ง์ฐ๊ณ configurationTest () ํ ์คํธ
โ memberRepository์ ์ธ์คํด์ค ๊ฐ์ด ๋ค๋ฅธ๊ฒ์ ์ ์ ์๊ณ ํ ์คํธ์ ์คํจํ๋ค.
โ ์ฑ๊ธํค์ด ๋ณด์ฅ๋์ง ์์.
โ ๊ฒฐ๋ก : @Bean๋ง ์ฌ์ฉํด๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก์ ๋๋ ์ฑ๊ธํค์ ๋ณด์ฅํ์ง ์๋๋ค.
๊ณ ๋ฏผํ ๊ฒ ์์ด ์คํ๋ง ์ค์ ์ ๋ณด๋ ํญ์ @Configuration์ ์ฌ์ฉํ์!