#6. ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น
by JiwonDev์์์ ์คํ๋ง์ด ๋์ค๊ฒ๋ ๊ฐ๋ ์ ๋ํด ์์๋ณด์๋ค๋ฉด, ์ด๋ฒ ๊ธ๋ถํฐ๋ ์คํ๋ง ์์ฒด๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ์์๋ณด์.
*ํด๋น ๊ธ์ ๊น์ํ๋์ ์ธํ๋ฐ ๊ฐ์๋ฅผ ๊ณต๋ถํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
# ์คํ๋ง ์ปจํ ์ด๋
//์คํ๋ง ์ปจํ
์ด๋ ์์ฑ
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(
memberRepository(),
discountPolicy());
}
... ์๋ต...
}
- ApplicationContext ๋ฅผ ์คํ๋ง ์ปจํ ์ด๋๋ผ ํ๋ค.
- ApplicationContext ๋ ์ธํฐํ์ด์ค์ด๋ค.
- ์ฐธ๊ณ ๋ก ์คํ๋ง ์ปจํ ์ด๋๋ ๋ณดํต ์ด๋ ธํ ์ด์ (@) ๊ธฐ๋ฐ์ ์๋ฐ ํด๋์ค๋ก ๋ง๋ค์ง๋ง, ๊ธฐ์กด์ ์๋ธ๋ฆฟ์ ์ค์ ํ๋ ๊ฒ์ฒ๋ผ XML ๊ธฐ๋ฐ์ผ๋ก๋ ๋ง๋ค ์ ์๋ค.
- ์๋ฐ ์ค์ ํด๋์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์คํ๋ง ์ปจํ
์ด๋(ApplicationContext)๋ฅผ ๋ง๋ค์ด๋ณด์.
- new AnnotationConfigApplicationContext(appConfig.class)
- ์ด ํด๋์ค๋ ApplicationContext ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด์ด๋ค.
์ฐธ๊ณ ๋ก ์ ํํ๋ ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ๋ถ๋ฅผ ๋ ์ต์์์ BeanFactory์ ์์์ธ ApplicationContext๋ฅผ ๊ตฌ๋ถํด์ ์ฌ์ฉํ์ง๋ง, ์ด๋ ๋์ค์ ์์๋ณด๋๋ก ํ์. (๋ณดํต BeanFactory๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๊ณ , AppContext๋ฅผ ์คํ๋ง ์ปจํ ์ด๋๋ผ๊ณ ํ๋ค.)
# ์คํ๋ง ์ปจํ ์ด๋์ ์์ฑ๊ณผ์
@1 ์ปจํ ์ด๋ ์์ฑ
ApplicationContext๋ผ๋ ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ๋ฑ๋กํด์ค์ ์ฌ์ฉํ๋ค. ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์์ฑ ํ ๋์๋ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ๊ตฌํ์ฒด์ ์ง์ ํด์ฃผ์ด์ผ ํ๋๋ฐ, ์ฌ๊ธฐ์์๋ AppConfig.class๋ฅผ ์ด์ฉํ์ฌ [์๋ฐ์ Class ๊ฐ์ฒด]๋ฅผ ํตํด ๊ตฌ์ฑ์ ๋ณด๋ฅผ ์ง์ ํ์๋ค. Class ๊ฐ์ฒด๊ฐ ๋ญ์ฃ ?
์๋ฐ๋ Object.class ๋ฅผ ํตํด ํด๋น ๊ฐ์ฒด์ Class ๊ฐ์ฒด๋ฅผ ๋ฐ์ ์ ์๋ค.
Class.forName("ํจํค์ง ์ ์ฒด ๊ฒฝ๋ก")
ํด๋์ค์ด๋ฆ.class
MyHello.class
Class.forName("mypackage.core.MyHello")
Class ํด๋์ค๋ ์๋ฐ์์ ์ฌ์ฉ๋๋ ํด๋์ค์ ๋ํ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ , ์ด๋ฅผ ์ ์ฅํ์ฌ ๋๊ฒจ์ค ์ ์๋ ๊ฐ์ฒด์ด๋ค.์ฆ ์ฝ๊ฒ๋งํด [ํด๋์ค์ ๊ตฌ์กฐ] ์์ฒด๋ฅผ ํ๋์ ํด๋์ค๋ก ํํํด๋์ ๊ฐ์ฒด๋ผ๋ ๋ง์ด๋ค.
์ฐธ๊ณ ๋ก ์ด๋ ๊ฒ ๊ฐ์ฒด๋ฅผ ํตํด [๋ค๋ฅธ ๊ฐ์ฒด]์ ์ ๋ณด๋ฅผ ๋ถ์ํ๋ ๋ฐฉ์์ Reflection ๊ธฐ๋ฒ์ด๋ผ๊ณ ํ๋ค. ํด๋์ค ํ์ผ์ ์์น๋ ์ด๋ฆ๋ง์ผ๋ก๋ ํด๋น ํด๋์ค์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๊ฒ(Hello.class) ๋ง๋ค์ด์ฃผ๋ ์ ์ฐํ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ด๋ค. ์คํ๋ง ํ๋ ์์ํฌ์์๋ ๋ฆฌํ๋ ์ ๊ธฐ๋ฒ์ ์์ฃผ ๋ง์ด ์ฌ์ฉ์๋ ๊ฑธ ๋ณผ ์ ์๋ค.
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
@2 ์คํ๋ง ๋น ๋ฑ๋ก
์ปจํ ์ด๋์ ํ๋ผ๋ฉํ๋ก ๋๊ฒจ์ค ๊ฐ์ฒด(AppConfig.class)์์ @Bean ์ผ๋ก ๋ฑ๋ก๋ ๋ฉ์๋๋ฅผ ์ ๋ถ ํธ์ถํ์ฌ ๋ฐํ ๊ฐ์ ์คํ๋ง ๋น ์ ์ฅ์์ ๋ชจ์๋๋ค. ๋น ์ด๋ฆ์ ๋ฉ์๋ ๋ช ์ผ๋ก ์ง์ ๋๋ฉฐ ์ํ๋ค๋ฉด ๋ฐ๊ฟ ์ ์๊ธดํ๋ค. @Bean(name="...") ์ฐธ๊ณ ๋ก ๋น์ ์ด๋ฆ์ ํญ์ ๋ค๋ฅด๊ฒ ๋ถ์ฌํด์ฃผ์ด์ผํ๋๋ฐ, ๊ฐ์ ์ด๋ฆ์ ๋ถ์ฌํ๋ฉด ๋น ์ ์ฅ์์์๋ ๊ธฐ์กด์ ๋น์ ๋ฎ์ด๋ฒ๋ฆฌ๊ฑฐ๋ ๋ฌด์๋์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. (* ์์ฆ์ ์คํ๋ง ๋ถํธ๊ฐ ์ด๋ฐ ์ค์ ์ค์๋ฅผ ์ค๋ฅ๋ก ๊ฐ๋ฐ์์๊ฒ ์๋ ค์ค๋ค. )
@3 ์คํ๋ง ๋น ์์กด๊ด๊ณ ์ค์
์ ์ฅ์์ ๋ฑ๋ก๋ ๋น๋ค์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ค. ์ค์ ์คํ๋ง ๋น์์ ์์กด๊ด๊ณ์ธ ๊ฐ์ฒด์ ์ฐธ์กฐ ๊ฐ๋ค์ด ์ฐ๊ฒฐ๋๋ค. ์ฐ๊ฒฐ์ด๋ผ๋๊ฒ ๋จ์ํ ์๋ฐ ๋ฉ์๋๋ฅผ ํธ์ถํด์ ์์ฑํ๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์์ง๋ง, ์ด์๋ ์ฐจ์ด๊ฐ ์๋ค. (*์ฑ๊ธํค ์ปจํ ์ด๋)
์ด์ฒ๋ผ ์คํ๋ง์ ๋น์ ์์ฑํ๋ ๋จ๊ณ์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ ๋จ๊ณ๊ฐ ๋๋์ด์ ธ ์๋ค. ํ์ง๋ง ์์ ์์ ์ฒ๋ผ ์๋ฐ ์ฝ๋๋ก ์คํ๋ง๋น์ ๋ฑ๋กํ๋ฉด ์์ฑ์๋ฅผ ํธ์ถํ๋ฉด์ ์์กด๊ด๊ณ ์ฃผ์ ๋ ํ๋ฒ์ ์ฒ๋ฆฌ๋๋๋ฐ, ์ด๋ ๋์ค์ '์์กด๊ด๊ณ ์๋ ์ฃผ์ '์ ๋ฐฐ์ฐ๋ฉด์ ์์๋ณด๋๋ก ํ์.
# ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ์คํ๋ง ๋น ์กฐํํ๊ธฐ
ํ ์คํธ ์ฝ๋(JUnit5)๋ฅผ ์ด์ฉํด ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๋ฐ์ดํฐ๋ฅผ ํ์ธํด๋ณด์. ์ฐธ๊ณ ๋ก ๋ฑ๋ก๋ ๋น๋ค์ ์ด๋ฆ์ AppContext ๊ฐ์ฒด์ ๋ฉ์๋๋ก ์ป์ด์ฌ ์ ์๋ค. ๋ด๊ฐ ๋ฑ๋กํ ๋น ์ด์ธ์ ์คํ๋ง์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉํ๋ ๋น๋ค๋ ์์์ ์ ์ํ์.
class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("๋ชจ๋ ๋น ์ถ๋ ฅํ๊ธฐ")
void findAllBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" + bean);
}
}
}
๋ํ getBeanDefinition์ ๋น๊ตํด์ ๋ด๊ฐ ๋ฑ๋กํ ์ดํ๋ฆฌ์ผ์ด์ ๋น(appConfig, memberService...)๋ง ํ์ธํ ์๋ ์๋ค.
import org.springframework.beans.factory.config.BeanDefinition;
@Test
@DisplayName("์ ํ๋ฆฌ์ผ์ด์
๋น ์ถ๋ ฅํ๊ธฐ")
void findApplicationBean() {
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition =
ac.getBeanDefinition(beanDefinitionName);
//Role ROLE_APPLICATION: ์ง์ ๋ฑ๋กํ ์ ํ๋ฆฌ์ผ์ด์
๋น
//Role ROLE_INFRASTRUCTURE: ์คํ๋ง์ด ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋น
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name=" + beanDefinitionName + " object=" +
bean);
}
}
}
@1 Bean ์กฐํ - ๊ธฐ๋ณธ
์์ ํ ์คํธ ์ผ์ด์ค๋ฅผ ๋ณด๋ฉด ์ ์ ์์๋ง, ๊ธฐ๋ณธ์ ์ผ๋ก ๋น์ AppContext์ ์๋ ๋ฉ์๋๋ก ์กฐํ ํ ์ ์๋ค. ๋ง์ฝ ํด๋น ๋น์ด ์กด์ฌํ์ง ์๋๋ค๋ฉด NoSuchBeanDefinitionException ๊ฐ ๋ฐ์ํ๋ค.
- getBean("Bean ์ด๋ฆ", ํ์ )
- getBean(ํ์ )
import org.junit.jupiter.api.Assertions; // Assertions๊ฐ ๊ฐ์ ์ด๋ฆ์ด 2๊ฐ์์ ์ ์ํ์.
import static org.assertj.core.api.Assertions.*;
class ApplicationContextBasicFindTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("๋น ์ด๋ฆ์ผ๋ก ์กฐํ")
void findBeanByName() {
MemberService memberService = ac.getBean("memberService",
MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("์ด๋ฆ ์์ด ํ์
๋ง์ผ๋ก ์กฐํ")
void findBeanByType() {
MemberService memberService = ac.getBean(MemberService.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("๊ตฌ์ฒด ํ์
์ผ๋ก ์กฐํ")
void findBeanByName2() {
MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.class);
assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}
@Test
@DisplayName("๋น ์ด๋ฆ์ผ๋ก ์กฐํ์คํจ")
void findBeanByNameX() {
//ac.getBean("xxxxx", MemberService.class); ํ
์คํธ
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
ac.getBean("xxxxx", MemberService.class));
}
}
* ํ ์คํธ ์ฝ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก, ์ญํ ๊ณผ ๊ตฌํ์ ๋ถ๋ฆฌํ๋๊ฒ ์ข๋ค. ์์ ์์ ์ฒ๋ผ ์คํ๋ง ๋น์ ์กฐํํ ๋ ๊ตฌํ์ฒด๋ฅผ ์ด์ฉํด ๊ตฌ์ฒด์ ์ผ๋ก ์กฐํํ๋ฉด ์ ์ฐ์ฑ์ด ๋จ์ด์ง์ ์ ์ํ์.
@2 Bean ์กฐํ - ๋์ผํ ํ์ ์ด 2๊ฐ ์ด์์ธ ๊ฒฝ์ฐ
getBean์ ์ด์ฉํด ํ์ ์ผ๋ก ๋น์ ์กฐํํ ์ ์๋ค ํ๋๋ฐ, ๋ง์ฝ ํ์ ์ด ๊ฐ๋ค๋ฉด ์ด๋ป๊ฒ ์กฐํํ ์ ์์๊น? ์ด๋ ac.getBeansOfType()์ ์ด์ฉํ์ฌ ํด๋น ํ์ ์ ๋ชจ๋ ๋น์ ์กฐํํ ์ ์๋ค.
* ํ ์คํธ๋ฅผ ํธํ๊ฒ ํ๊ธฐ์ํด ์ฝ๋์์ ๊ฐ๋จํ๊ฒ ํ ์คํธ์ฉ AppConfig ๊ฐ์ฒด(SameBeanConfig)๋ฅผ ๋ง๋ค์๋ค.
class ApplicationContextSameBeanFindTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
@DisplayName("ํ์
์ผ๋ก ์กฐํ์ ๊ฐ์ ํ์
์ด ๋ ์ด์ ์์ผ๋ฉด, ์ค๋ณต ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค")
void findBeanByTypeDuplicate() {
//DiscountPolicy bean = ac.getBean(MemberRepository.class);
assertThrows(NoUniqueBeanDefinitionException.class, () ->
ac.getBean(MemberRepository.class));
}
@Test
@DisplayName("ํ์
์ผ๋ก ์กฐํ์ ๊ฐ์ ํ์
์ด ๋ ์ด์ ์์ผ๋ฉด, ๋น ์ด๋ฆ์ ์ง์ ํ๋ฉด ๋๋ค")
void findBeanByName() {
MemberRepository memberRepository = ac.getBean("memberRepository1",
MemberRepository.class);
assertThat(memberRepository).isInstanceOf(MemberRepository.class);
}
@Test
@DisplayName("ํน์ ํ์
์ ๋ชจ๋ ์กฐํํ๊ธฐ")
void findAllBeanByType() {
Map<String, MemberRepository> beansOfType =
ac.getBeansOfType(MemberRepository.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " +
beansOfType.get(key));
}
System.out.println("beansOfType = " + beansOfType);
// ๊ฐ์ ํ์
์ 2๊ฐ์ฌ์ผ ํ๋ค.
assertThat(beansOfType.size()).isEqualTo(2);
}
// ํ
์คํธ์ฉ AppConfig ์ฌ์ฉ. ํ
์คํธ๋ผ์ ๋์ถฉ ๋ง๋ค์๋ค.
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
@3 Bean ์กฐํ - ์์๊ด๊ณ
๋ถ๋ชจ ํ์ ์ผ๋ก ์กฐํํ๋ฉด, ์์ ํ์ ๋ ํจ๊ป ์กฐํํ๋ค. ์ฆ Object๋ก ์กฐํํ๋ฉด ๋ชจ๋ ์คํ๋ง ๋น์ด ๋์ค๊ฒ ๋๋ค. ์ค๋ณต์ ํ์ธํ ๋ ์์๊ด๊ณ๋ฅผ ์ ์ํ์ฌ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ํ์.
class ApplicationContextExtendsFindTest {
AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(TestConfig.class);
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ์กฐํ์, ์์์ด ๋ ์ด์ ์์ผ๋ฉด, ์ค๋ณต ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค")
void findBeanByParentTypeDuplicate() {
//DiscountPolicy bean = ac.getBean(DiscountPolicy.class);
assertThrows(NoUniqueBeanDefinitionException.class, () ->
ac.getBean(DiscountPolicy.class));
}
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ์กฐํ์, ์์์ด ๋ ์ด์ ์์ผ๋ฉด, ๋น ์ด๋ฆ์ ์ง์ ํ๋ฉด ๋๋ค")
void findBeanByParentTypeBeanName() {
DiscountPolicy rateDiscountPolicy = ac.getBean("rateDiscountPolicy",
DiscountPolicy.class);
assertThat(rateDiscountPolicy).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("ํน์ ํ์ ํ์
์ผ๋ก ์กฐํ")
void findBeanBySubType() {
RateDiscountPolicy bean = ac.getBean(RateDiscountPolicy.class);
assertThat(bean).isInstanceOf(RateDiscountPolicy.class);
}
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ๋ชจ๋ ์กฐํํ๊ธฐ")
void findAllBeanByParentType() {
Map<String, DiscountPolicy> beansOfType =
ac.getBeansOfType(DiscountPolicy.class);
assertThat(beansOfType.size()).isEqualTo(2);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value=" +
beansOfType.get(key));
}
}
@Test
@DisplayName("๋ถ๋ชจ ํ์
์ผ๋ก ๋ชจ๋ ์กฐํํ๊ธฐ - Object")
void findAllBeanByObjectType() {
Map<String, Object> beansOfType = ac.getBeansOfType(Object.class);
for (String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value=" +
beansOfType.get(key));
}
}
@Configuration
static class TestConfig {
@Bean
public DiscountPolicy rateDiscountPolicy() {
return new RateDiscountPolicy();
}
@Bean
public DiscountPolicy fixDiscountPolicy() {
return new FixDiscountPolicy();
}
}
}
'๐ฑ Spring Framework > Spring Core' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
#7. ์คํ๋ง์ ์ฑ๊ธํค ์ปจํ ์ด๋ (@Configuration) (0) | 2021.08.02 |
---|---|
BeanFactory, BeanDefinition (+ ์คํ๋ง ์ปจํ ์ด๋ XML ์ค์ ) (0) | 2021.08.02 |
#5 ์คํ๋ง์ผ๋ก ์ ํํ๊ธฐ (0) | 2021.08.02 |
IoC, DI, ๊ทธ๋ฆฌ๊ณ ์ปจํ ์ด๋ (0) | 2021.08.02 |
#4 ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ(SOC), ์์กด์ฑ ์ฃผ์ (DI) (0) | 2021.08.02 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev