DevLog ๐ถ
[Spring] ์คํ๋ง์ ์ด์ฉํด ํ์-์ฃผ๋ฌธ ์๋น์ค ๊ฐ๋ฐ, ์คํ๋ง ์ปจํ ์ด๋์ ์ฑ๊ธํค ๋ณธ๋ฌธ
[Spring] ์คํ๋ง์ ์ด์ฉํด ํ์-์ฃผ๋ฌธ ์๋น์ค ๊ฐ๋ฐ, ์คํ๋ง ์ปจํ ์ด๋์ ์ฑ๊ธํค
dolmeng2 2022. 8. 6. 22:56- ๊น์ํ ๋์ '์คํ๋ง ํต์ฌ์๋ฆฌ - ๊ธฐ๋ณธํธ'์ ๋ณด๊ณ ์ ๋ฆฌํ ๊ธ์ ๋๋ค ๐
- ์ง๋ ํฌ์คํ ๊ณผ ์ด์ด์ง๋๋ค :D
- ์ง๋ ํฌ์คํ ์์, ์์ ์๋ฐ๋ง์ ์ด์ฉํด ํ์ - ์ฃผ๋ฌธ, ๊ทธ๋ฆฌ๊ณ ํ ์ธ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ์๋ค.
- SRP, OCP, DIP๋ฅผ ๋ง์กฑํ๋๋ก ์ค๊ณํ์์ผ๋, ์ฌ์ฉ์๊ฐ ์ง์ Config๋ฅผ ๊ด๋ฆฌํด์ผ ํ๋ ๋ฑ ๋ฒ๊ฑฐ๋ก์ด ๋ถ๋ถ๋ค์ด ์๊ฒผ๋ค.
- ๊ทธ๋ฌ๋, ์คํ๋ง์์๋ ์ด๋ฅผ ๋ค ํ๋ ์์ํฌ ๋จ์๋ก ๋๊ธฐ๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๊ฐ ์์กด๊ด๊ณ๋ฅผ ๋น๊ต์ ๋ ์ ๊ฒฝ์จ๋ ๋๋ค!
| ์ ์ด์ ์ญ์ - IoC (Inversion of Control)
- ๊ธฐ์กด์๋ ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ AppConfig๊ฐ ๊ฐ์ง๊ณ ์์๋ค. ๊ฐ ํด๋ผ์ด์ธํธ๋ ์ด๋ค ๊ตฌํ ๊ฐ์ฒด๊ฐ ๋ค์ด์ค๋์ง ๋ชจ๋ฅธ๋ค!
- ์ด๋ฐ ์์ผ๋ก, ํ๋ก๊ทธ๋จ์ ์ ์ด ํ๋ฆ์ ์ธ๋ถ์์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ ์ด์ ์ญ์ ์ด๋ค.
- ์ฐธ๊ณ ๋ก, ํ๋ ์์ํฌ๊ฐ ๋ด๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ์ ์ดํ๊ณ ์คํํ๋ค๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ 'ํ๋ ์์ํฌ'๋ผ๊ณ ํ๋ค.
- ๊ทธ๋ฐ ์๋ฏธ๋ก ์คํ๋ง ์ญ์ ์ผ์ข ์ ํ๋ ์์ํฌ์ด๋ค.
| ์์กด๊ด๊ณ ์ฃผ์ - DI (Dependency Injection)
- ์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ : ์คํํ์ง ์์๋ ์์กด๊ด๊ณ ๋ถ์ ๊ฐ๋ฅ.
- ๋จ์ํ OrderServiceImpl์ด MemberRepository์ DiscountPolicy๋ฅผ ์์กดํ๊ณ ์์.
- ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด๊ด๊ณ : ์คํ ์์ ์ ๊ตฌํ ๊ฐ์ฒด๋ฅผ ์ธ๋ถ์์ ์์ฑํ๊ณ , ํด๋ผ์ด์ธํธ์ ์ ๋ฌํด์ ์์กด๊ด๊ณ ์ฐ๊ฒฐ
- ์ค์ ๋ก DiscountPolicy์ Fix๊ฐ ๋ค์ด๊ฐ์ง, Rate๊ฐ ๋ค์ด๊ฐ์ง.
- ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ , ๊ฐ ์ฐธ์กฐ๊ฐ์ ์ ๋ฌํด์ ์ฐ๊ฒฐํ๋ค.
- ์์กด๊ด๊ณ ์ฃผ์ ์ ์ฌ์ฉํ๋ฉด, ์ ์ ์ธ ํด๋์ค ์์กด๊ด๊ณ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ , ๋์ ์ธ ๊ฐ์ฒด ์ธ์คํด์ค ์์กด๊ด๊ณ๋ฅผ ์ฝ๊ฒ ๋ณ๊ฒฝํ ์ ์๋ค.
๐ฉ AppConfig์ฒ๋ผ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ฉด์, ์์กด๊ด๊ณ๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ๊ฒ IoC Container / DI Container๋ผ๊ณ ํ๋ค.
- ์ด์ , ์ฐ๋ฆฌ๊ฐ ์งฐ๋ ์ฝ๋์ ์คํ๋ง์ ์ ์ฉํด๋ณด์.
[AppConfig.java]
@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 FixDiscountPolicy();
}
}
- @Configuration, @Bean์ด๋ผ๋ ์ด๋ ธํ ์ด์ ์ด ๋ถ์ ๊ฑธ ํ์ธํ ์ ์๋ค.
- ์คํ๋ง ์ปจํ ์ด๋์ @Bean์ด ๋ถ์ ๋ฉ์๋๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค!
- ์ด๋ ๊ฒ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ ์น๊ตฌ๋ฅผ ๊บผ๋ด๊ธฐ ์ํด์๋, ApplicationContext๋ฅผ ์ฌ์ฉํ๋ค.
public class MemberApp {
public static void main(String[] args) {
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService =
applicationContext.getBean("memberService", MemberService.class);
}
}
- ์ฌ๊ธฐ์ ApplicationContext๊ฐ ๋ฐ๋ก ์คํ๋ง ์ปจํ ์ด๋์ด๋ฉฐ, ์ด๋ ๊ตฌ์ฑ ์ ๋ณด๋ก @Configuration์ด ๋ถ์ AppConfig๋ฅผ ์ฌ์ฉํ๋ค.
- โ ์ดํ, @Bean์ด ๋ถ์ ๋ฉ์๋๋ฅผ ๋ชจ๋ ํธ์ถํ์ฌ ๋ฐํ๋ ๊ฐ์ฒด๋ฅผ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํ๋ฉฐ, ๊ฐ๊ฐ์ ์คํ๋ง ๋น์ด ๋๋ค.
- @Bean์ด ๋ถ์ ๋ฉ์๋ ๋ช ์ด ๊ณง ๋น์ ์ด๋ฆ์ด ๋๋ค. ac.getBean(bean_name)์ผ๋ก ์ฐพ์์ฌ ์ ์๋ค!
- ์คํ๋ง ์ปจํ ์ด๋๋ก ๊ด๋ฆฌํ๋ฉด ๋ญ๊ฐ ์ข์๊น?
| ์คํ๋ง ์ปจํ ์ด๋ (ApplicationContext)
- ApplicationContext๋ ์ธํฐํ์ด์ค๋ก ๋์ด ์์ผ๋ฉฐ, XML, ํน์ ์ ๋ ธํ ์ด์ ๊ธฐ๋ฐ์ ์๋ฐ ์ค์ ํด๋์ค๋ก ๋ง๋ค ์ ์๋ค.
- ์์ฆ์ XML๋ณด๋ค๋ ๋๋ถ๋ถ ์ด๋ ธํ ์ด์ ์ ํตํด์ ๋ง๋๋ ๊ฒ ๊ฐ๋ค.
โ ์คํ๋ง ์ปจํ ์ด๋ ์์ฑ
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
- ์คํ๋ง ์ปจํ ์ด๋ ์์ฑ ์, ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ์ง์ ํด์ฃผ์ด์ผ ํ๋ค.
- ์คํ๋ง ์ปจํ ์ด๋ ๋ด๋ถ์ ๋น ์ ์ฅ์์๋ ๋น ์ด๋ฆ๊ณผ ์ค์ ๋น ๊ฐ์ฒด ์ฃผ์๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
โ ์คํ๋ง ๋น ๋ฑ๋ก
- ์ค์ ์ ๋ณด ํด๋์ค์ ๋ฑ๋ก๋ @Bean ๋ฉ์๋ ์ ๋ณด๋ฅผ ํตํด ์คํ๋ง ๋น์ ๋ฑ๋กํ๋ค.
- ๋น ์ด๋ฆ์ ๋ฉ์๋ ์ด๋ฆ or @Bean(name="") ์๋ ์ง์ ๊ฐ๋ฅ!
๐ฉ ๋น ์ด๋ฆ์ ํญ์ ๋ค๋ฅธ ์ด๋ฆ์ ๋ถ์ฌํด์ผ ํ๋ค. ์๋๋ฉด ์คํํ ๋ ์๋ฌ๋๋ค...! (๊ทธ๋์ ์ฌ๋งํ๋ฉด ์๋ ์ง์ ์ ํ๋ ๊ฒ ๋์ ๋ฏ)
โ ์คํ๋ง ๋น ์์กด๊ด๊ณ ์ค์ - ์ค๋น
- ๊ฐ ๋น์ ํด๋นํ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
๐์ค๋น ๋จ๊ณ์ ์๋ฃ ๋จ๊ณ๋ฅผ ๋๋์ด๋์๋ค. ์ด์ ๋ ์ถํ ํฌ์คํ ์ผ๋ก ๋ค๋ฃจ๊ฒ ๋ค.
โ ์คํ๋ง ๋น ์์กด๊ด๊ณ ์ค์ - ์๋ฃ
- ์ค์ ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํด์ ์์กด๊ด๊ณ๋ฅผ ์ฃผ์ ํ๋ค.
- ์ค์ ๋ก, ์ฝ๋์์ ์ฐ๋ฆฌ๊ฐ ๋ฑ๋กํ ๋น์ ํ์ธํด๋ณด์.
[ApplicationContextInfoTest.java]
public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac
= new AnnotationConfigApplicationContext(AppConfig.class);
@Test
public void findAllBean() throws Exception {
// given
String[] names = ac.getBeanDefinitionNames();
List<String> registBean = new ArrayList<>();
System.out.println("get All Bean");
for(String name: names) {
Object bean = ac.getBean(name);
BeanDefinition definition = ac.getBeanDefinition(name);
System.out.println("name = " + name + " bean = " + bean);
if(definition.getRole() == BeanDefinition.ROLE_APPLICATION) {
registBean.add(name);
}
}
System.out.println("์ง์ ๋ฑ๋กํ ์ ํ๋ฆฌ์ผ์ด์
๋น");
for(String name : registBean) {
System.out.println("name = " + name);
}
}
}
โ ์คํ ๊ฒฐ๊ณผ
<get All Bean>
name = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
bean = org.springframework.context.annotation.ConfigurationClassPostProcessor@27a0a5a2
name = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
bean = org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@7692cd34
name = org.springframework.context.annotation.internalCommonAnnotationProcessor
bean = org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@33aa93c
name = org.springframework.context.event.internalEventListenerProcessor
bean = org.springframework.context.event.EventListenerMethodProcessor@32c0915e
name = org.springframework.context.event.internalEventListenerFactory
bean = org.springframework.context.event.DefaultEventListenerFactory@106faf11
name = appConfig
bean = study.springstudy.config.AppConfig$$EnhancerBySpringCGLIB$$33662889@70f43b45
name = memberService
bean = study.springstudy.domain.service.MemberServiceImpl@26d10f2e
name = orderService
bean = study.springstudy.domain.service.OrderServiceImpl@10ad20cb
name = memberRepository
bean = study.springstudy.domain.repository.MemoryMemberRepository@7dd712e8
name = discountPolicy
bean = study.springstudy.domain.service.discount.FixDiscountPolicy@2c282004
<์ง์ ๋ฑ๋กํ ์ ํ๋ฆฌ์ผ์ด์ ๋น>
name = appConfig
name = memberService
name = orderServicename = memberRepository
name = discountPolicy
โ ์คํ๋ง ๋ด๋ถ์์ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ๋ ๋น
- ConfigurationClassPostProcessor
: @Configuration์ด ๋ฑ๋ก๋ ๋น ๊ฐ์ฒด์์ @Bean์ด ๋ถ์ด ์๋ ๋น ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋กํ๋ค.
- AutowiredAnnotationBeanPostProcessor
: @Autowired์ ๋ํ ์์กด ์ฃผ์ ์ฒ๋ฆฌ๋ฅผ ์งํํ๋ค. @Autowired๊ฐ ์ ์ฉ๋ ํ๋, ์์ฑ์, ๋ฉ์๋์ ์๋ง์ ์์กด ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ๋ค.
- CommonAnnotationBeanPostProcessor
: JSR-250 (@PostConstruct ๋ฑ)์ ๋ํ ๋ผ์ดํ์ฌ์ดํด ์ฒ๋ฆฌ๋ฅผ ์งํํ๋ค.
- EventListenerMethodProcessor
: EventListener ๋ฉ์๋๋ฅผ ๊ฐ๋ณ ApplicationListener ์ธ์คํด์ค๋ก ๋ฑ๋กํ๋ค. (๋ถํ์ค)
- DefaultEventListenerFactory
: @EventListener๋ฅผ ์ฒ๋ฆฌํ๋ค. (๋ถํ์ค)
โ ์ง์ ๋ฑ๋กํ ๋น
- AppConfig
- memberService -> memberServiceImpl
- orderService -> orderServiceImpl
- memberRepository -> MemoryMemberRepository
- discountPolicy -> FixDiscountPolicy
| ์คํ๋ง ๋น ์กฐํํ๊ธฐ
- ac.getBean(bean_name, type)
- ac.getBean(type)
: ์ด๋ฆ+ํ์ , ํน์ ํ์ ์ผ๋ก ์กฐํํ ์ ์๋ค.
@Test
public void findBeanTest() throws Exception {
// ๋น ์ด๋ฆ์ผ๋ก ์กฐํ
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
assertThat(memberService1).isInstanceOf(MemberServiceImpl.class);
// ํ์
์ผ๋ก ์กฐํ
MemberService memberService2 = ac.getBean(MemberService.class);
assertThat(memberService2).isInstanceOf(MemberServiceImpl.class);
// ๊ตฌ์ฒด ํ์
์กฐํ - ์ ์ฐ์ฑ ๋จ์ด์ง
MemberServiceImpl memberService3 = ac.getBean("memberService", MemberServiceImpl.class);
assertThat(memberService3).isInstanceOf(MemberServiceImpl.class);
}
- ๋ง์ฝ, ๋์ผํ ํ์ ์ ๊ฐ์ง๊ณ ์๋ ๋น์ด ์ฌ๋ฌ ๊ฐ๊ฐ ์กด์ฌํ๋ค๋ฉด ์ด๋ป๊ฒ ํ ๊น?
- ์ด๋, ํ์ ์กฐํ๋ฅผ ์ฌ์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค. (NoUniqueBeanDefinitionException)
- ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ ์ด์์ผ ๊ฒฝ์ฐ๋ ๋น ์ด๋ฆ ์กฐํ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค. (ac.getBean(bean_name, type))
- ๋์ผํ ํ์ ์ ๊ฐ์ง๊ณ ์๋ ๋น์ ์กฐํํ๋ ค๋ฉด ac.getBeansOfType()์ ์ฌ์ฉํ๋ค.
public class ApplicationContextInfoTest {
AnnotationConfigApplicationContext ac2 = new
AnnotationConfigApplicationContext(SameBeanConfig.class);
@Test
public void findAllBeanByType() throws Exception {
Map<String, MemberRepository> beansOfType =
ac2.getBeansOfType(MemberRepository.class);
System.out.println("beansOfType = " + beansOfType);
for(String key : beansOfType.keySet()) {
System.out.println("key = " + key + " value = " + beansOfType.get(key));
}
assertThat(beansOfType.size()).isEqualTo(2);
}
@Configuration
static class SameBeanConfig {
@Bean
public MemberRepository memberRepository1() {
return new MemoryMemberRepository();
}
@Bean
public MemberRepository memberRepository2() {
return new MemoryMemberRepository();
}
}
}
โ ์คํ ๊ฒฐ๊ณผ
beansOfType = {memberRepository1=study.springstudy.domain.repository.MemoryMemberRepository@78e16155, memberRepository2=study.springstudy.domain.repository.MemoryMemberRepository@54a3ab8f}
key = memberRepository1 value = study.springstudy.domain.repository.MemoryMemberRepository@78e16155
key = memberRepository2 value = study.springstudy.domain.repository.MemoryMemberRepository@54a3ab8f
- ์์๋ก Config ํด๋์ค๋ฅผ ์ ์ธํด์ค์ ๋์ผํ ํ์ ์ ๊ฐ์ง ๋น์ ์์ฑํ์๋ค.
- ์์ฒ๋ผ MemberRepository ํ์ ์ ๊ฐ์ง ๋น์ด ์ ์กฐํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. (Map ํํ๋ก, ๋น ์ด๋ฆ๊ณผ ๊ตฌํ์ฒด๊ฐ ๋์จ๋ค)
- ๋ํ, ๋ถ๋ชจ ํ์ ์ผ๋ก ์กฐํ ์ ์์์ด ๋ ์ด์์ด๋ผ๋ฉด ๋น ์ด๋ฆ ์กฐํ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ฉฐ,
์ฌ๋ฌ ๊ฐ๋ฅผ ์กฐํํ๊ณ ์ถ๋ค๋ฉด ์์ฒ๋ผ getBeansOfType()์ ์ฌ์ฉํ๋ฉด ๋๋ค.
| BeanFactory vs ApplicationContext
โ BeanFactory
: ์คํ๋ง ์ปจํ ์ด๋์ ์ต์์ ์ธํฐํ์ด์ค. getBean()์ ์ ๊ณตํ๋ค.
โ ApplicationContext
: BeanFactory๋ฅผ ์์๋ฐ๋๋ค. ๋น ์กฐํ ์ธ์๋ ์๋ง์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
- MessageSource : ๊ตญ์ ํ ๊ธฐ๋ฅ (message.properties)
- EnvironmentCapable : profile, property ๊ด๋ฆฌ ๊ธฐ๋ฅ.
- profile : ํน์ ํ ์คํ ํ๊ฒฝ์์ ์ฌ์ฉํ๋ ๋น ๊ทธ๋ฃน ๋๋๊ธฐ (@Profile)
- property : ์ ํ๋ฆฌ์ผ์ด์ ๊ตฌ๋ ์ ํ์ํ ์ ๋ณด๋ฅผ key-value ํํ๋ก ์ ์ํ ์ ์์ผ๋ฉฐ, ์ฐ์ ์์๊ฐ ๋์ ์์ผ๋ก ๊ฐ์ ธ์จ๋ค.
- ApplicationEventPublisher : ์ด๋ฒคํธ ํ๋ก๊ทธ๋๋ฐ์ ํ์ํ ๊ธฐ๋ฅ ์ ๊ณต (@EventListener)
- ResourceLoader : ํ์ผ, ํด๋์คํจ์ค, ์ธ๋ถ ๋ฑ์์ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค. (ResourceLoader.getResource)
| BeanDefinition
- ์์ ์ ๊น ์ธ๊ธํ์์ง๋ง, ์คํ๋ง์์๋ ์ค์ ์ ๋ณด๋ฅผ xml, ํน์ ์ด๋ ธํ ์ด์ ์ ํตํด์ ๋ฑ๋กํ ์ ์๋ค.
- ์คํ๋ง์์๋ ์ด๋ป๊ฒ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ค์ ์ ๋ณด๋ฅผ ๋ฑ๋กํ ์ ์๋๋ก ํ์์๊น?
๐ฉ ๋ฐ๋ก, BeanDefinition์ ํตํ ์ถ์ํ ๋๋ถ์ด๋ค.
- XML์ด๋ , ์๋ฐ ์ฝ๋๋ BeanDefinition์ ๋ง๋ค๊ธฐ๋ง ํ๋ค๋ฉด ์คํ๋ง ์ปจํ ์ด๋๋ ์ค์ง BeanDefinition์ ์์กดํ๋ค.
- BeanDefinition์ ๋น ์ค์ ์ ๋ณด๋ผ๊ณ ํ๋ฉฐ, @Bean, <bean>๋น ํ๋์ฉ ๋ฉํ ์ ๋ณด๊ฐ ์์ฑ๋๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ ์ด๋ฌํ ๋ฉํ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์คํ๋ง ๋น์ ์์ฑํ๋ค.
โ ๊ตฌ์ฒด์ ์ธ ์์ฑ ๋ฐฉ์
- AnnotationConfigApplicationContext๋ AnnotatedBeanDefinitionReader๋ฅผ ํตํด์ ์๋ฐ ์ฝ๋ ๊ธฐ๋ฐ ์ค์ ์ ๋ณด(@Configuration)๋ฅผ ์ฝ์ด ์์ฑ.
- GenericXmlApplicationContext๋ XmlBeanDefinitionReader๋ฅผ ํตํด์ XML์ ์ฝ์ด ์์ฑ.
- ์ฆ, ์ด๋ฐ ์์ผ๋ก Reader๋ฅผ ํตํด BeanDefinition์ ๋ง๋ค์ด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
โ BeanDefinition์ ์ด๋ค ์ ๋ณด๋ค์ด ์์๊น?
- BeanClassName : ์์ฑํ ๋น์ ํด๋์ค ๋ค์. (์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์์๋ null)
- factoryBeanName: ํฉํ ๋ฆฌ ์ญํ ์ ๋น ๋ค์(appConfig)
- factoryMethodName: ๋น์ ์์ฑํ ๋ฉ์๋ (memberService)
- Scope: ๊ธฐ๋ณธ์ ์ผ๋ก ์ฑ๊ธํค์ด๋ค.โญ
- lazyInit: ์ปจํ ์ด๋ ์์ฑ ์ ๋น์ด ์์ฑ๋๋ ๊ฒ์ด ์๋, ์ค์ ์ฌ์ฉ ์์ ์ ๋น์ ์ฌ์ฉํ๋๋ก ์ง์ฐ ์ฒ๋ฆฌ ์ฌ๋ถ
- InitMethodName: ๋น ์์ฑ ํ ์์กด๊ด๊ณ ์ ์ฉํ์ ๋ ํธ์ถ๋๋ ์ด๊ธฐํ ๋ฉ์๋ ๋ค์
- DestroyMethodName: ๋น ์๋ฉธ ํ ์ ๊ฑฐ ์ง์ ์ ํธ์ถ๋๋ ๋ฉ์๋ ๋ค์
- Constructor arguments, Properties: ์์กด๊ด๊ณ ์ฃผ์ ์์ ์ฌ์ฉํ๋ ์ค์ . (์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์์๋ null)
| Singleton Pattern
- ์คํ๋ง์ด ์ ๊ณตํ๋ DI ์ปจํ ์ด๋์ ๊ฒฝ์ฐ, ์ฑ๊ธํค์ ๋ณด์ฅํ๋ค.
โ ์ฑ๊ธํค์ด๋?
: ํด๋์ค์ ์ธ์คํด์ค๊ฐ 1๊ฐ๋ง ์์ฑ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ๋์์ธ ํจํด.
โ ์ฑ๊ธํค์ ์คํํ ์ ์๋ ๋ฐฉ๋ฒ
public class SingletonService {
private static final SingletonService service = new SingletonService();
public static SingletonService getService() {
return service;
}
private SingletonService() {
}
}
- ์์ฑ์๋ฅผ private์ผ๋ก ๋์๊ธฐ ๋๋ฌธ์, SingletonService ๊ฐ์ฒด๋ฅผ ์ธ๋ถ์์ new๋ก ์์ฑํ ์ ์๋ค.
- static ์์ญ์ ์ ์ธํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ฑ 1๊ฐ๋ง ์์ฑํด๋๋ค. final๋ก ์ ์ธํ ๊ฒ์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ง ์์ผ๋๊น.
(๐ฉ static ํค์๋๋ฅผ ๋ถ์ด๋ฉด ๋ด๋ถ์ ์ผ๋ก ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ํ ๋ฒ๋ง ์ํํ๋ค = ๊ฐ์ ๊ณณ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ง ๋ฐ๋ผ๋ณธ๋ค.)
- service๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ getService() ๋ฉ์๋๋ง public์ผ๋ก ์ด์ด๋์๋ค.
์์ผ๋ก SingletonService์ service๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด์๋ getService() ๋ฉ์๋๋ก๋ง ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
- ์ฌ๊ธฐ์ singletonService1, 2๋ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ฃผ์๋ฅผ ๋ฐ๋ผ๋ณด๊ฒ ๋๋ค. ๊ฐ์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋๊น!
โ ๊ทธ๋ฌ๋, ์ฑ๊ธํค ํจํด์...
- ์ฝ๋ ๊ตฌํ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ๋ก์ง์ด ์ง์ ๋ถํด์ง๋ค.
- DIP๋ฅผ ์๋ฐํ๋ค. ๊ตฌ์ฒด ํด๋์ค์ ์์กดํ๊ธฐ ๋๋ฌธ์! -> OCP๋ฅผ ์๋ฐํ ์๋ ์๋ค.
- ํ ์คํธํ๊ธฐ๊ฐ ์ด๋ ค์ฐ๋ฉฐ, ๋ด๋ถ ์์ฑ ๋ณ๊ฒฝ์ด ์ด๋ ต๋ค. -> ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ ์ฑ๊ธํค ํจํด์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ฉด์๋, ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌํ๋ค!
- ์คํ๋ง ์ปจํ ์ด๋๊ฐ ๊ณง ์ฑ๊ธํค ์ปจํ ์ด๋๊ฐ ๋๋ฉฐ, ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ์ ์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ๋ผ๊ณ ํ๋ค.
- ๋๋ถ์ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ฝ๋๋ฅผ ์ฝ์ ํ ํ์๋ ์์ผ๋ฉฐ, DIP, OCP๋ก๋ถํฐ ์์ ๋กญ๊ฒ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค!
@Test
void springContainer() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService1 = ac.getBean("memberService",
MemberService.class);
MemberService memberService2 = ac.getBean("memberService",
MemberService.class);
// memberService1 = study.springstudy.domain.service.MemberServiceImpl@6a175569
System.out.println("memberService1 = " + memberService1);
// memberService2 = study.springstudy.domain.service.MemberServiceImpl@6a175569
System.out.println("memberService2 = " + memberService2);
assertThat(memberService1).isSameAs(memberService2);
}
- ํ์ธํด๋ณด๋ฉด, ์์ฒญ์ด ์ฌ ๋๋ง๋ค ๊ฐ์ฒด๋ฅผ ์์ฑํ์ง ์๊ณ ์ด๋ฏธ ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ฅผ ๋ค์ ๋ฐํํด์ค๋ค!
โ ์ฑ๊ธํค ์ฃผ์์ฌํญ
- ํ๋์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์, statelessํ๊ฒ ์ค๊ณํด์ผ ํ๋ค.
- ๊ฐ๊ธ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํด์ผ ํ๋ค. (๊ฐ์ ๋ณ๊ฒฝํ๊ฒ ๋๋ฉด ์ํ)
- ์คํ๋ง ๋น์ ํ๋์ ๊ณต์ ๊ฐ์ ์ ๋์ ๋ ์ค์ ํ์ง ๋ง ๊ฒ.
| @Configuration๊ณผ Singleton
- ์คํ๋ง์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ฑ๊ธํค์ ๋ณด์ฅํ๋ค.
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
// bean = class study.springstudy.config.AppConfig$$EnhancerBySpringCGLIB$$30df2dad
System.out.println("bean = " + bean.getClass());
}
@Configuration์ ์ฌ์ฉํ๋ฉด AppConfig bean์ ํ์ธํด ๋ณด๋ฉด ํ๋ก์ ๊ฐ์ฒด์ธ ๊ฑธ ๋ณผ ์ ์๋ค! (CGLIB)
: ์ฐธ๊ณ ๋ก, AppConfig@CGLIB๋ AppConfig๋ฅผ ์์๋ฐ์์ ๊ตฌํํ๋ค. (๊ทธ๋์ AppConfig.class๋ก getBean ์กฐํ๊ฐ ๊ฐ๋ฅํ ๊ฒ. ๋ถ๋ชจ ํ์ ์ด๋๊น)
์ฆ, ์คํ๋ง ๋น์ ๋ฑ๋กํ ๋ ๋ด๋ถ์ ์ผ๋ก ์ค์ AppConfig ๋์ ํ๋ก์ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฑ๋กํ๋ ๊ฒ์ด๋ค.
๋ด๋ถ์ ์ผ๋ก @Bean์ด ๋ถ์ ๋ฉ์๋๋ง๋ค ์ด๋ฏธ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก๋์ด ์๋ค๋ฉด, ์ปจํ ์ด๋์์ ์ฐพ์์ ๋ฐํํด์ฃผ๊ณ ,
์์ผ๋ฉด ๊ธฐ์กด์ ๋ก์ง์ ํธ์ถํ์ฌ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ค์ ์คํ๋ง ์ปจํ ์ด๋์ ๋ฑ๋ก์ํค๋ ๊ณผ์ ์ ํตํด ๋์ ์ผ๋ก ์คํ๋ง ๋น์ ๋ฑ๋ก ๋ฐ ๋ฐํํ๋ค.
๋ง์ฝ, AppConfig์ @Configuration์ ๋ถ์ด์ง ์๊ณ ๋จ์ํ @Bean๋ง ๋ถ์ด๋ฉด CGLIB์ ์ฌ์ฉํ์ง ์์ผ๋ฉฐ, ์ฑ๊ธํค ์ญ์ ๋ณด์ฅํ์ง ์๋๋ค.
๐ฉ ์ฆ, ์ค์ง์ ์ธ ์ฑ๊ธํค ๋ณด์ฅ์ @Configuration์ ํตํด ์ด๋ฃจ์ด์ง๋ฉฐ, @Bean์ ์คํ๋ง ๋น ๋ฑ๋ก ์ญํ ๋ง ํ๋ค.
์ฐ๋ฆฌ๋ ์ง๊ธ๊น์ง @Configuration, @Bean์ ํตํด ๋น์ ๋ฑ๋กํ์๋๋ฐ, ์ด๋ฅผ ๋ ์๋ํ์ํฌ ์๋ ์์๊น?
-> ์ปดํฌ๋ํธ ์ค์บ์ ์ด์ฉํ์! ์ด๋ ๋ค์ ํฌ์คํ ์์ ๋ค๋ฃจ๊ฒ ๋ค.
'Back-end > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] WAS, ์๋ธ๋ฆฟ, ๋ฉํฐ ์ค๋ ๋์ ์ค๋ ๋ ํ (0) | 2022.08.08 |
---|---|
[Spring] ๋น ์๋ช ์ฃผ๊ธฐ ์ฝ๋ฐฑ, ๋น ์ค์ฝํ (0) | 2022.08.07 |
[Spring] ์ปดํฌ๋ํธ ์ค์บ๊ณผ ์์กด๊ด๊ณ ์๋ ์ฃผ์ (0) | 2022.08.07 |
[Spring] ์์ ์๋ฐ๋ก ํ์-์ฃผ๋ฌธ ์๋น์ค ๊ฐ๋ฐํ๊ธฐ (0) | 2022.08.06 |
[Spring] ์คํ๋ง์ด๋? (3) | 2022.08.06 |