-
[๊ฐ์] ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ 3SPRING/INFLEARN 2021. 5. 16. 20:40
์ด๋ฒ์ฃผ ์ ๋ง๋ค... ํ์ดํ ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ - ์ธํ๋ฐ | ๊ฐ์
์คํ๋ง ์ ๋ฌธ์๊ฐ ์์ ๋ฅผ ๋ง๋ค์ด๊ฐ๋ฉด์ ์คํ๋ง์ ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์คํ๋ง ๊ธฐ๋ณธ๊ธฐ๋ฅผ ํ์คํ ๋ค์ง ์ ์์ต๋๋ค., ์คํ๋ง ํต์ฌ ์๋ฆฌ๋ฅผ ์ดํดํ๊ณ , ์ฑ์ฅํ๋ ๊ฐ๋ฐ์๊ฐ ๋์ด๋ณด์ธ์! ๐ฃ ํ์ธํด์ฃผ
www.inflearn.com
์ถ์ฒ: ๊น์ํ ๊ฐ์ฌ๋ ์คํ๋ง ํต์ฌ ์๋ฆฌ- ๊ธฐ๋ณธํธ
4.์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น
- ์คํ๋ง ์ปจํ ์ด๋ ์์ฑ
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
ApplicationContext <- ์คํ๋ง ์ปจํ ์ด๋, ์ธํฐํ์ด์ค
์คํ๋ง ์ปจํ ์ด๋๋ ์ฃผ๋ก ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์๋ฐ ์ค์ ํฌ๋์ค๋ก ๋ง๋ ๋ค (XML๋ก ๋ง๋ค๊ธฐ๋, ์ ์์)
์คํ๋ง ์ปจํ ์ด๋ ์์ฑ
-> ํ๋ผ๋ฏธํฐ๋ก ๋์ด์จ ์ค์ ํด๋์ค ์ ๋ณด๋ฅผ ๊ตฌ์ฑ ์ ๋ณด๋ก ์ฌ์ฉํ์ฌ
์ ๋ ธํ ์ด์ ๋ถ์ ๊ฒ๋ค์ ์ฐพ์๋ค๋๋ฉด์ ์คํ๋ง ๋น ๋ฑ๋ก* ๋น ์ด๋ฆ์ ๋ชจ๋ ๋ฌ๋ผ์ผํ๋ค.
-> ์คํ๋ง ์ปจํ ์ด๋๊ฐ ์ค์ ํด๋์ค ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํ์ฌ ์์กด๊ด๊ณ ์ฃผ์
- ์ปจํ ์ด๋์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์กฐํ
ApplicationContextInfoTest.java๋ก ์กฐํํ๋ค.
์ด๋ ๊ฒ ํ๋ฉด ์ฐ๋ฆฌ๊ฐ ์ง ์ฝ๋์์ ์ฐ์ด๋ ๊ฒ ๋ฟ ์๋๋ผ ์คํ๋ง ๋ด๋ถ์ ๋น๊น์ง ๋ค ๋์จ๋ค.
์๋ ๋ค์ฏ๊ฐ ์์๋๋ก AppConfig, ๋ฑ๋กํ ๋น๋ค
๋ฐ๋ผ์ ์๋์ ์ฐ๋ฆฌ๊ฐ ์ง ์ฝ๋์์ ์ฐ์ด๋ ๊ฒ๋ค๋ง ์ถ๋ ฅํ๋๋ก ๋ง๋ค์๋ค.
์ ๋์จ๋ค.
ac.getBeanDefinitionNames() : ์คํ๋ง์ ๋ฑ๋ก๋ ๋ชจ๋ ๋น ์ด๋ฆ ์กฐํ
ac.getBean(๋น ์ด๋ฆ) : ๋น ์ด๋ฆ์ผ๋ก ๋น ๊ฐ์ฒด ์กฐํgetRole() ->
ROLE_APPLICATION : ์ฌ์ฉ์ ์ ์ ๋น
ROLE_INFRASTRUCTURE : ์คํ๋ง์ด ๋ด๋ถ์์ ์ฌ์ฉํ๋ ๋นsoutv ๊ฐ System.out.println์ผ๋ก ์ถ๋ ฅ
ctrl + D ๋ณต์
- ์คํ๋ง ๋น ์กฐํ - ๊ธฐ๋ณธ
getBean์ ์ฌ์ฉํ๋ 3๊ฐ์ง ๋ฐฉ๋ฒ
1) ๋น ์ด๋ฆ์ผ๋ก ์กฐํ
2) ํ์ ์ผ๋ก๋ง ์กฐํ
3) ๊ตฌ์ฒด ํ์ ์ผ๋ก ์กฐํ
//ApplicationContextBasicFindTest.java public 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(){ MemberService memberService = ac.getBean("memberService", MemberServiceImpl.class); //์ข์ ๋ฐฉ๋ฒ์ ์๋๋ค. ์ด์จ๋ ๋ฑ๋กํ ๋ฐํํ์ ๋ฟ ์๋๋ผ ๊ตฌ์ฒดํ ํ์ ์ผ๋ก ํด๋ ์๊ด์ด ์๋ค. assertThat(memberService).isInstanceOf(MemberServiceImpl.class); } @Test @DisplayName("๋น ์ด๋ฆ์ผ๋ก ์กฐํํ๋๋ฐ ์๋ ์ด๋ฆ") void findBeanByNameX(){ /*MemberService memberService = ac.getBean("xxxx", MemberService.class); //No bean named 'xxxx' available ์ค๋ฅ ๋ฌ๋ค.*/ org.junit.jupiter.api.Assertions.assertThrows(NoSuchBeanDefinitionException.class, () -> ac.getBean("xxxx", MemberService.class)); } }
- ์คํ๋ง ๋น ์กฐํ - ๋์ผํ ํ์ ์ด ๋ ์ด์
AppConfig๋ฅผ ์๋ก ๋ง๋ค์ด์ ์๊น์ ๊ฐ์ ๋ฐฉ์์ผ๋ก ํ ์คํธ ํ๋ฉด ํ๋๋ง ์ฐพ์์ ธ์ผ ํ์ง๋ง ๋๊ฐ๊ฐ ์ฐพ์์ก๋ค๋ ์ค๋ฅ๊ฐ ๋ฌ๋ค.
//ApplicationContextSameBeanFindTest.java public class ApplicationContextSameBeanFindTest { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class); @Test @DisplayName("ํ์ ์ผ๋ก ์กฐํ์ ๊ฐ์ ํ์ ์ด ๋ ์ด์ ์์ผ๋ฉด, ์ค๋ณต ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.") void findBeanByTypeDuplicate(){ //MemberRepository bean = ac.getBean(MemberRepository.class); Assertions.assertThrows(NoUniqueBeanDefinitionException.class, () -> ac.getBean(MemberRepository.class)); } @Test @DisplayName("ํ์ ์ผ๋ก ์กฐํ์ ๊ฐ์ ํ์ ์ด ๋ ์ด์ ์์ผ๋ฉด, ๋น ์ด๋ฆ์ ์ง์ ํ๋ฉด ๋๋ค.") void findBeanName(){ MemberRepository memberRepository = ac.getBean("memberRepository", 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); assertThat(beansOfType.size()).isEqualTo(2); } //AppConfig ์ค๋ณต ์๋ ๊ฑธ๋ก ์๋ก ๋ง๋ค๊ธฐ @Configuration static class SameBeanConfig{ @Bean public MemberRepository memberRepository(){ return new MemoryMemberRepository(); } @Bean public MemberRepository memberRepository2(){ return new MemoryMemberRepository(); } } }
๊ฐ์ ํ์ ์ด ๋ ์ด์์ผ ๊ฒฝ์ฐ, ๋ฐ์ ๋น ์ด๋ฆ์ ์ง์ ์ ํ๊ณ ํ์ ์ผ๋ก ์กฐํํ๋ฉด Mapํด๋์ค๊ฐ ๋์จ๋ค.
์ ์ผํ๊ฒ ์ถ๋ ฅ์ด ์์๋ ๋ฉ์๋ ์ถ๋ ฅ ์๋จ - ์คํ๋ง ๋น ์กฐํ - ์์ ๊ด๊ณ
๋์์น : ๋ถ๋ชจ ํ์ ์ผ๋ก ์กฐํํ๋ฉด ์์ ํ์ ์ ํจ๊ป ์กฐํ๋๋ค.
//ApplicationContextExtendsFindTest.java public class ApplicationContextExtendsFindTest { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class); @Test @DisplayName("๋ถ๋ชจ ํ์ ์ผ๋ก ์กฐํ์ ์์์ด ๋ ์ด์ ์์ผ๋ฉด ์ค๋ณต ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค") void findBeanByParentTypeDuplicate(){ 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); //๊ตฌ์ฒด์ ์ธ rate์ด์ฉ๊ตฌ๋ ํ๋๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ํ์ ์ผ๋ก ํ๋ฒ์ ์ ์ฐพ์ ์ ์๋ค. } @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 Type") 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 FicDiscountPolicy(); } } }
๋ถ๋ชจ ํ์ ์ผ๋ก ๋ชจ๋ ์กฐํ ์์ฃผ ์ ๋จ ์ฝ๋์ ์๋ ๊ฒ ๋ฟ ์๋๋ผ ์คํ๋ง ๋ด๋ถ์ ๋น๊น์ง ์ฐ๋ฅด๋ฅด~ ๋ชจ๋ Object์ ํ์ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ด๋ค. - BeanFactory์ ApplicationContext
BeanFactory
์คํ๋ง ์ปจํ ์ด๋์ ์ต์์ ์ธํฐํ์ด์ค
์คํ๋ง ๋น ๊ด๋ฆฌ, ์กฐํ↓์์
ApplicationContext
BeanFactory ๊ธฐ๋ฅ์ ๋ชจ๋ ์์๋ฐ์์ ์ ๊ณตํ์ง๋ง BeanFactory ๋ฟ ์๋๋ผ ๋ง์ ๋ค๋ฅธ ๊ธฐ๋ฅ๋ค๋ ์์๋ฐ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์๋ BeanFactory ์ธ์๋ ์ ๋ง์ ๋ถ๊ฐ๊ธฐ๋ฅ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
- MessageSource
๊ตญ์ ํ ex) ํ๊ตญ์์ ๋ค์ด์ค๋ฉด ํ๊ตญ์ด๋ก, ์์ด๊ถ์์ ๋ค์ด์ค๋ฉด ์์ด๋ก ์ถ๋ ฅ - EnviromentCapable
ํ๊ฒฝ ๋ณ์. ๋ก์ปฌ, ๊ฐ๋ฐ, ์ด์๋ฑ์ ๊ตฌ๋ถํด์ ์ฒ๋ฆฌ ex) ํ๊ฒฝ ๋ณ๋ก ์ด๋ค DB์ ์ฐ๊ฒฐํ๋์ง - ApplicationEventPublisher
์ด๋ฒคํธ๋ฅผ ๋ฐํํ๊ณ ๊ตฌ๋ ํ๋ ๋ชจ๋ธ์ ํธ๋ฆฌํ๊ฒ ์ง์ - ResourseLoader
ํ์ผ, ํด๋์คํจ์ค, ์ธ๋ถ ๋ฑ์์ ๋ฆฌ์์ค๋ฅผ ํธ๋ฆฌํ๊ฒ ์กฐํ
- ๋ค์ํ ์ค์ ํ์ ์ง์ - ์๋ฐ ์ฝ๋, XML
์๋ฐ ์ฝ๋ ๋ฟ ์ด๋๋ผ XML ๋ฑ ๋ค์ํ ํ์์ ์ง์ํ๋ค.
ApplicationContext์
1) AnnotationConfigApplicationContext์ ์๋ฐ ์ฝ๋ ๋๊ธฐ๊ธฐ
2) GenericXmlApplication์ xml ํ์ผ ๋๊ธฐ๊ธฐ <- ํ์ฌ๋ ๊ฑฐ์ ์ฌ์ฉ๋์ง ์์
<!--appConfig.xml--> <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="memberService" class="hello.core.member.MemberServiceImpl"> <constructor-arg name="memberRepository" ref="memberRepository" /> </bean> <bean id="memberRepository" class="hello.core.member.MemoryMemberRepository" /> <bean id="orderService" class="hello.core.order.OrderServiceImpl"> <constructor-arg name="memberRepository" ref="memberRepository" /> <constructor-arg name="discountPolicy" ref="discountPolicy" /> </bean> <bean id="discountPolicy" class="hello.core.discount.RateDiscountPolicy" /> </beans>
์ ๋ณด๋ฉด AppConfig.java ๋ ์์ ๋๊ฐ์ ๊ฒ์ ์ ์ ์๋ค.
ApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml");๋ก๋ง ๋ฐ๊ฟ์ ๋๊ฐ์ด ํ ์คํธํ๋ฉด ์ ๋๋ค!
- ์คํ๋ง ๋น ์ค์ ๋ฉํ ์ ๋ณด - BeanDefinition
์คํ๋ง ์ปจํ ์ด๋๋ ์๋ฐ ์ฝ๋์ธ์ง, XML์ธ์ง ๋ชฐ๋ผ๋ ๋๋ค.
์ด๋ ๊ฒ ๋ค์ํ ๋ฐฉ๋ฒ์ ์ง์ํ๋ ์ด์ ๋ ๋ชจ๋ BeanDefinition์ด๋ผ๋ ์ถ์ํ๋ก ์ธ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.BeanDefinition์ ์ค์ ๋ฉํ ์ ๋ณด๋ผ๊ณ ํ๋ค. @Bean๋น ํ๋์ ๋ฉํ์ ๋ณด๋ฅผ ๋ง๋ค์ด๋ธ๋ค.
app config ํ์ผ์ ํ์์ ๋ง๋ reader๋ก ์ค์ ์ ๋ณด๋ฅผ ์ฝ๊ณ ๋น ๋ฉํ์ ๋ณด๋ฅผ ์์ฑํ๋ค. //BeanDefinitionTest.java public class BeanDefinitionTest { AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext(AppConfig.class); //GenericXmlApplicationContext ac = new GenericXmlApplicationContext("appConfig.xml"); @Test @DisplayName("๋น ์ค์ ๋ฉํ์ ๋ณด ํ์ธ") void findApplicationBean(){ String[] beanDefinitionNames = ac.getBeanDefinitionNames(); for(String beanDefinitionName : beanDefinitionNames){ BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName); if(beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){ System.out.println("beanDefinition = " + beanDefinition + " beanDefinition = " + beanDefinition); } } } }
๋น์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ์ง์ ๋ฑ๋ก, Factory ๋ฉ์๋๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด ์๋๋ฐ.
์ ์ฅ๋๋ ํ์์ด ์กฐ๊ธ ๋ค๋ฆ
5.์ฑ๊ธํค ์ปจํ ์ด๋
- ์น ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์ฑ๊ธํค
์คํ๋ง์ ์ฃผ๋ก ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ๋๋๋ฐ ์น์ ๋ณดํต ์ฌ๋ฌ ๊ณ ๊ฐ์ด ๋์์ ์์ฒญํ๋ค.
->์์ฒญ์ด ์ฌ ๋๋ง๋ค ๊ฐ์ฒด๋ฅผ ์๋ก ๋ง๋๋๊ฐ?
yes ๋๊ฐ ์์ฑ๋จ ํ์ง๋ง ๊ฐ์ ๊ฐ์ฒด ์ฌ๋ฌ๊ฐ๊ฐ ๋งค๋ฒ ์๊ธฐ๋ ๊ฒ์ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น!
-> ํ๋์ ๊ฐ์ฒด๋ก ๊ณต์ ํ๋๋ก : ์ฑ๊ธํค ํจํด
- ์ฑ๊ธํค ํจํด
ํด๋์ค์ ์ธ์คํด์ค๊ฐ ๋ฑ 1๊ฐ๋ง ์์ฑ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ๋์์ธ ํจํด
-> ๋๊ฐ์ด์ ์์ฑ๋์ง ๋ชปํ๋๋ก ๋ง๋๋ค.
//SingletonService.java public class SingletonService { //static์ ๊ฐ์ฒด ์ฌ๋ ค๋๊ธฐ private static final SingletonService instance = new SingletonService(); //์กฐํ public static SingletonService getInstance(){ return instance; } //์์ฑ์๋ฅผ private๋ก ๋ง๋๋ค *** private SingletonService(){ } public void logic(){ System.out.println("์ฑ๊ธํค ๊ฐ์ฒด ๋ก์ง ํธ์ถ"); } }
์ด์ ๋ ๊ฐ์ฒด๊ฐ ๊ฐ์ ๊ฒ์ ๋ณผ ์ ์๋ค! ํ์ง๋ง ๋จ์ :
์ฝ๋๊ฐ ๋ง์ด ๋ค์ด๊ฐ(Singleton Service)
ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กด DIP, OCP์๋ฐ
ํ ์คํธํ๊ธฐ ์ด๋ ค์
private๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์ ์ฐ์ฑ์ด ๋จ์ด์ง
๋ฑ๋ฑ ๊ฐ๊ฐ์ง ๋จ์ ๋ค์ด ์๋ค.
๊ทธ๋ฌ๋!! ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ฑ๊ธํค์ ์์์ ๊ตฌํํด์ค๋ค!!
- ์ฑ๊ธํค ์ปจํ ์ด๋
Bean์ ์๊ฐํด๋ณด๋ฉด, ์คํ๋ง์ ํ ํด๋์ค ๋น ๊ฐ์ฒด ํ๋์ฉ๋ง ๋ฑ๋กํด์ ๊ด๋ฆฌํ๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ก ์ฌ์ฉํ๋ ์ฑ๊ธํค์ ์์ ๋จ์ ๋ค์ ๋ชจ๋ ํด๊ฒฐํ ์ ์๋ค.
๊ฐ์ ๊ฐ์ฒด์์ ํ์ธํ ์ ์๋ค. ์คํ๋ง์ ์ฑ๊ธํค ๋ฟ ์๋๋ผ ๋งค๋ฒ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํด ๋ฐํํ๋ ๊ธฐ๋ฅ๋ ์ ๊ณตํ๋ค.
- ์ฑ๊ธํค ๋ฐฉ์์ ์ฃผ์์
์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ํ๋์ ๊ฐ์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๊ธํค ๊ฐ์ฒด๋ ์ํ๋ฅผ ์ ์งํ๊ฒ ์ค๊ณํ๋ฉด ์๋๋ค.
-> ๋ฌด์ํ ์ค๊ณ
ํน์ ํด๋ผ์ด์ธํธ์ ์์กด์ ์ด๋ฉด ์๋จ
ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ ์์ ์ด ๋ถ๊ฐ๋ฅํด์ผํจ, ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํ๋ฉด ์ข์ํ๋ ๋์ ์ง์ญ๋ฒ์, ํ๋ผ๋ฏธํฐ, ThreadLocal๋ฑ์ ์ฌ์ฉํด์ผ ํจ
๋ฌธ์ ์ํฉ
//StatefulService.java public class StatefulService { private int price; public void order(String name, int price){ System.out.println("name = " + name + " price = " + price); this.price = price; } public int getPrice(){ return price; } }
//StatefulServiceTest.java public class StatefulServiceTest { @Test void statefulServiceSingleton(){ ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class); StatefulService statefulService1 = ac.getBean(StatefulService.class); StatefulService statefulService2 = ac.getBean(StatefulService.class); //ThreadA: A๊ฐ 10000์ ์ฃผ๋ฌธ statefulService1.order("userA", 10000); //ThreadB: B๊ฐ 20000์ ์ฃผ๋ฌธ statefulService2.order("userB", 20000); //ThreadA: A ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ int price = statefulService1.getPrice(); System.out.println("price = " + price); //์ค๊ฐ์ ์ฌ์ฉ์ B๊ฐ ๋ฐ๊พธ์ด๋ฒ๋ ธ์ผ๋ฏ๋ก price๋ 20000์์ด ๋์ค๊ฒ ๋๋ค. //๊ฐ์ ๊ฐ์ฒด์ด๋ฏ๋ก ์๊ธฐ๋ ๋ฌธ์ Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000); } static class TestConfig{ @Bean public StatefulService statefulService(){ return new StatefulService(); } } }
์๋ผ!! userA๋ ์ด๋ง์์ง๋ฆฌ๋ฅผ ์ฃผ๋ฌธํ์ง ์์์ด!! ํด๊ฒฐ
//StatefulService.java public class StatefulService { public int order(String name, int price){ System.out.println("name = " + name + " price = " + price); return price; } }
//StatefulServiceTest.java public class StatefulServiceTest { @Test void statefulServiceSingleton(){ ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class); StatefulService statefulService1 = ac.getBean(StatefulService.class); StatefulService statefulService2 = ac.getBean(StatefulService.class); //ThreadA: A๊ฐ 10000์ ์ฃผ๋ฌธ int userAPrice = statefulService1.order("userA", 10000); //ThreadB: B๊ฐ 20000์ ์ฃผ๋ฌธ int userBPrice = statefulService2.order("userB", 20000); //ThreadA: A ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ System.out.println("price = " + userAPrice); //๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. Assertions.assertThat(userAPrice).isEqualTo(10000); } static class TestConfig{ @Bean public StatefulService statefulService(){ return new StatefulService(); } } }
ํธ-์ - @Configuration๊ณผ ์ฑ๊ธํค
memberService ๋น -> memberRepository() ํธ์ถ -> MemoryMemberRepository() ํธ์ถ
orderService ๋น -> memberRepository() ํธ์ถ -> MemoryMemberRepository() ํธ์ถ=> ์ฑ๊ธํค์ด ๊นจ์ง๋ ๊ฒ ์๋๊ฐ?!
ํ์ง๋ง ์คํ๋ง์ ์ฑ๊ธํค์ ๋ณด์ฅํด์ค๋ค.
//MemberServiceImpl.java public class MemberServiceImpl implements MemberService{ /*์๋ต*/ public MemberRepository getMemberRepository(){ return memberRepository; } } //OrderServiceImpl.java public class OrderServiceImpl implements OrderService{ /*์๋ต*/ public MemberRepository getMemberRepository(){ return memberRepository; } }
//ConfigurationSingletonTest.java public class ConfigurationSingletonTest { @Test void configurationTest(){ ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); //memberService ํธ์ถ memberRepository MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class); //orderService ํธ์ถ memberRepository OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class); //์ฒ์์ ๋น์ ๋ฑ๋ก๋ memberRepository MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class); MemberRepository memberRepository1 = memberService.getMemberRepository(); MemberRepository memberRepository2 = orderService.getMemberRepository(); System.out.println("memberService -> memberRepository = " + memberRepository1); System.out.println("orderService -> memberRepository = " + memberRepository2); System.out.println("memberRepository = " + memberRepository); assertThat(memberService.getMemberRepository()).isSameAs(memberRepository); assertThat(orderService.getMemberRepository()).isSameAs(memberRepository); } }
์ธ๊ฐ ๋ชจ๋ ๊ฐ๋ค...! AppConfig์ DP์ ์ ์ธํ ๊ฐ Bean์ ํธ์ถ๋ ๋๋ง๋ค ์ถ๋ ฅ๋๋ call+soutm๋ฌธ์ฅ์ ๋ฃ์ด๋์๋ค.
๊ทธ๋ฆฌ๊ณ ์ถ๋ ฅํ๋ ์์(๋ฑ๋ก MS->MR, ๋ฑ๋ก MR, ๋ฑ๋ก OS->MR)๊ณผ ๋ค๋ฅด๊ฒ ๋์จ๋ค!
๊ฐ ํ ๋ฒ ์ฉ ์ธ ๋ฒ๋ง ๋์ค๊ณ ๋ง๋ค! - @Configuration๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์์ ๋ง๋ฒ
์คํ๋ง ์ปจํ ์ด๋๋ ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ด ๋๋๋ก ๋ณด์ฅํด์ฃผ์ด์ผ ํ๋ค. ๊ทธ๋ฌ๋ ์๋ฐ ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ํ๊ธฐ๋ ์ด๋ ต๋ค.
Appconfig๊ฐ ์๋ ๋ค์ ์ด์ํ๊ฒ ๋ถ์ ํด๋์ค๊ฐ ์ถ๋ ฅ๋๋ค. ์ด๋ฐ ์์์ ๋ค๋ฅธ ํด๋์ค๊ฐ ์ฑ๊ธํค์ ๋ณด์ฅํด์ค๋ค.(CGLIB) <- ์ด๋ ์์ ํ์ ์ด๋ค.
์๊ฐ ์คํ๋ง ๋น์ด ์ด๋ฏธ ์์ผ๋ฉด ์คํ๋ง ๋น ๋ฐํ, ์์ผ๋ฉด ๋ฑ๋กํ๋ ์ญํ ์ ํ๋ค.
๋ํ ๋ค์ ์ด์ํ ์ด๋ฆ์ด ๋ถ์ ํด๋์ค์ฌ๋, ์๋ ํด๋์ค ์ด๋ฆ์ผ๋ก ์กฐํ ๊ฐ๋ฅํจ
์ด๋ @Configuration ๋๋ถ์ด๋ค.
@Configuration์ ์ ์ฉํ์ง ์๋๋ค๋ฉด, ์ฑ๊ธํค์ด ๋ณด์ฅ๋์ง ์๋๋ค!
์์ํ AppConfig์ ์ ๊ทผํ์ฌ @Bean๋ค์ ์ธ์ํด์ ๋ฑ๋กํจ
์๊น ์์ํ๋ ๋ฑ๋ก MS->MR, ๋ฑ๋ก MR, ๋ฑ๋ก OS->MR, ์ฆ, MemberRepositiory๊ฐ ์ธ๋ฒ ์ถ๋ ฅ๋๋ค.
-> ์ฑ๊ธํค์ด ๋ณด์ฅ๋์ง ์๋๋ค!, ์คํ๋ง ์ปจํ ์ด๋์ ๊ด๋ จ์ด ์์ด์ง
์ ๋ถ ์คํ์์ผ๋ณด๋ฉด ์ธ๋ฒ ๋ง๋ค์ด์ง๋ MemberRepositiory์ ์ธ์คํด์ค๊ฐ ๊ฐ๊ฐ ๋ค ๋ค๋ฅธ ๊ฒ ๋ํ ์ ์ ์๋ค.
@Autowired์ฐ๊ธฐ๋ ํ๊ณ ์ด์ฉ๊ธด ํ์ง๋ง ๊ทธ๋๋
๊ฒฐ๋ก : ์์ด์ผ ํจ
6.์ปดํฌ๋ํธ ์ค์บ
- ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋ ์ฃผ์ ์์ํ๊ธฐ
@Bean์ผ๋ก ์ผ์ผํ ๋ฑ๋กํ๋ ๊ฒ์ ์คํ๋ง ๋น์ด ๋ง์์ง๋ฉด ํ๋ค์ด์ง
->Component scan, Autowired
//AutoAppConfig.java @Configuration @ComponentScan( excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Configuration.class) //์์ ์ ์ง ์ํด ์ ์ธํ ๊ฒ๋ค ์ค์ , Appconfig ๋ ๋ถ๋ชํ๊น๋ด ์ผ๋จ ์ค์ ) public class AutoAppConfig { }
์ด๋ @Component๊ฐ ๋ถ์ ํด๋์ค๋ฅผ ์ค์บํด์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
//AutoAppConfigTest.java public class AutoAppConfigTest { @Test void basicScan(){ AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class); MemberService memberService = ac.getBean(MemberService.class); assertThat(memberService).isInstanceOf(MemberService.class); } }
MemoryMemberRepository @Component ์ถ๊ฐ
RateDiscountPolicy @Component ์ถ๊ฐ
MemberServiceImpl @Component, ์์ฑ์์ @Autowired ์ถ๊ฐ(์์กด ๊ด๊ณ ์ฃผ์ )OrderServiceImpl @Component, ์์ฑ์์ @Autowired ์ถ๊ฐ
๊ทธ๋ฆฌ๊ณ ํ ์คํธ๋ฅผ ํด๋ณธ๋ค.
//AutoAppConfigTest.java public class AutoAppConfigTest { @Test void basicScan(){ AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class); MemberService memberService = ac.getBean(MemberService.class); assertThat(memberService).isInstanceOf(MemberService.class); } }
์ ๋์๊ฐ๋ ๊ฒ์ ์ ์ ์๋ค.
๋น์ ์ฌ๋ผ๊ฐ๋ ์ด๋ฆ์ ๋ฐ๊พธ๊ณ ์ถ์ผ๋ฉด @Component(๋ฐ๊พธ๊ณ ์ถ์ ์ด๋ฆ)ํ๋ฉด ๋๋ค. (๊ธฐ๋ณธ์ ๋งจ์๋ง ์๋ฌธ์์ธ ํด๋์ค ์ด๋ฆ)
@ComponentScan์ @Component ๊ฐ ๋ถ์ ๋ชจ๋ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค.
@Autowired๋์คํ๋ง ์ปจํ ์ด๋๊ฐ ์๋์ผ๋ก ํด๋น ์คํ๋ง ๋น์ ์ฐพ์์ ์ฃผ์
ex) OrderServiceImpl์ ์์ฑ์ ํ๋ผ๋ฏธํฐ memberRepository์ discountPolicy๊ฐ์ ์ ๋ค์ ์ด๋ฏธ ์๋ ๊ฒ์ด๋๊น
ํด๋น ์คํ๋ง ๋น์ ์ฐพ์์ ์ฃผ์ . getBean์ฌ์ง
- ํ์ ์์น์ ๊ธฐ๋ณธ ์ค์บ ๋์
@ComponentScan(
basePackages = "ํ์ํ ํจํค์ง์ ํ์ ์์ ์์น (Default : @ComponentScan ์ด ๋ถ์ ์ค์ ์ ๋ณด ํด๋์ค์ ํจํค์ง)",basePackageClasses = ์ง์ ํ ํด๋์ค์ ํจํค์ง๋ฅผ ํ์ ์์ ์์น๋ก ์ง์ ํ๋ค.
}Springboot์์๋ @SpringBootApplication์ด ์๋์ผ๋ก ์์ฑ๋๋๋ฐ, ๊ทธ ์๋์๋ ComponentScan์ด ์์
-> ์ธ ํ์ ์์
@Component : ์ปดํฌ๋ํธ ์ค์บ์์ ์ฌ์ฉ
@Controlller : ์คํ๋ง MVC ์ปจํธ๋กค๋ฌ์์ ์ฌ์ฉ
@Service : ์คํ๋ง ๋น์ฆ๋์ค ๋ก์ง์์ ์ฌ์ฉ (๋ณ ๊ธฐ๋ฅ์ ์์, ๋ณด๊ธฐ ์ข์)
@Repository : ์คํ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต์์ ์ฌ์ฉ, ๋ฐ์ดํฐ ๊ณ์ธต์ ์์ธ๋ฅผ ์คํ๋ง ์์ธ๋ก ๋ณํ
@Configuration : ์คํ๋ง ์ค์ ์ ๋ณด์์ ์ฌ์ฉ, ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ ์ ์งํ๋๋ก ์ถ๊ฐ ์ฒ๋ฆฌ-> ์ด ๊ฒ๋ค ์๋์ ์ ๋ถ @Component์์
์๋ฐ์๋ ์๋ ธํ ์ด์ ์์ ๊ธฐ๋ฅ์ด ์์ผ๋ฏ๋ก ์ด๊ฑธ ํ ์ ์๋ ๊ฒ์ ์คํ๋ง์ด ์ง์ํ๋ ๊ธฐ๋ฅ์ด๋ค.
- ํํฐ
includeFilters : ์ปดํฌ๋ํธ ์ค์บ ๋์ ์ถ๊ฐ ์ง์
excludeFilters : ์ปดํฌ๋ํธ ์ค์บ ์ ์ธํ ๋์์ค์บ ๋์/ ์ ์ธ ์ ๋ ธํ ์ด์
//MyIncludeComponent.java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyIncludeComponent { } //MyExcludeComponent.java @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyExcludeComponent { }
์ค์บ ๋์ ํด๋์ค(BeanA)์๋ @MyIncludeComponent๋ฅผ,
์ค์บ ์ ์ธ ํด๋์ค(BeanB)์๋ @MyExcludeComponent๋ฅผ ๋ถ์ฌ์ค๋๋ค.
์ค์ ์ ๋ณด์ ์ค์บ ๋์/์ ์ธ ํ ์คํธ ์ฝ๋
//ComponentFilerAppConfigTest.java public class ComponentFilerAppConfigTest { @Test void filterScan(){ ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class); BeanA beanA = ac.getBean("beanA", BeanA.class); assertThat(beanA).isNotNull(); assertThrows( NoSuchBeanDefinitionException.class, ()->ac.getBean("beanB", BeanB.class) ); } @Configuration @ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) static class ComponentFilterAppConfig { } }
์ ์ธ๋ B๋ getBean์ด ์๋๋ฏ๋ก assertTrows์ ๋ฃ๋๋ค.
A๋ ํฌํจ๋์๊ธฐ์ Null์ด ์๋๋ฏ๋ก ์ค๋ฅ๊ฐ ๋์ง ์๋๋ค.
- ์ค๋ณต ๋ฑ๋ก๊ณผ ์ถฉ๋
FilterType. ANNOTATION: ๊ธฐ๋ณธ๊ฐ, ์ ๋ ธํ ์ด์ ์ ์ธ์ํด์ ๋์ํ๋ค.(์๋ตํด๋ ๋จ)
ASSIGNABLE_TYPE: ์ง์ ํ ํ์ ๊ณผ ์์ ํ์ ์ ์ธ์ํด์ ๋์ํ๋ค.
ASPECTJ: AspectJ ํจํด ์ฌ์ฉ
REGEX: ์ ๊ท ํํ์
CUSTOM: TypeFilter ์ด๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํด์ ์ฒ๋ฆฌ์ค๋ณต๋ฑ๋ก
์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก - ์์์ ์ค๋ฅ๋จ
ex) @Component("service") ๋ฌ๋ฆฐ ํด๋์ค๊ฐ ๋ ๊ฐ์์๋ ๋น ๋ฑ๋ก vs ์๋ ๋น ๋ฑ๋ก - ์๋์ด ์๋์ ์ค๋ฒ๋ผ์ด๋ฉ ํ๋ค.
ex) @Component๋ฌ๋ฆฐ ํด๋์ค๊ณผ @Bean("์ ํด๋์ค ์ด๋ฆ") - ํ์๊ฐ ์ ์ ์ค๋ฒ๋ผ์ด๋
=> ํผํ๋ ๊ฒ ์ข๋ค, ์ ๋งคํ ์ํฉ์ ๊ตณ์ด ๋ง๋ค ํ์๊ฐ ์๋?
์๋๋ฐ, ์ต๊ทผ ์คํ๋ง๋ถํธ์์๋ ์๋& ์๋์ด ์ถฉ๋ํ๋ฉด ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ก ๋ณ๊ฒฝํจ
- ๋ฐ์ํ์ง ์๋๋ก ํ ์๋ ์์ ํ์ง๋ง ์ด์จ๋ ์ด๋ฆ ๊ฒน์น๋๊ฑด ๋ณ๋ก์
'SPRING > INFLEARN' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๊ฐ์] ๋ชจ๋ ๊ฐ๋ฐ์๋ฅผ ์ํ HTTP ์น ๊ธฐ๋ณธ ์ง์ 1 (0) 2021.07.21 [๊ฐ์] ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ 4 (0) 2021.05.25 [๊ฐ์] ์คํ๋ง ํต์ฌ ์๋ฆฌ- ๊ธฐ๋ณธํธ 2 (0) 2021.05.12 [๊ฐ์] ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ 1 (0) 2021.05.04 [๊ฐ์] ์คํ๋ง ์ ๋ฌธ - ์ฝ๋๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ๋ถํธ, ์น MVC, DB์ ๊ทผ ๊ธฐ์ 3 (0) 2021.04.05 - MessageSource