μ΄μ κΈ - μ€νλ§ κΈ°μ΄μ μ리λ₯Ό μμ보μπ³ μμ μμ±λ μμ μ½λλ₯Ό κΈ°λ°μΌλ‘ λ΄μ©μ μμ±λμμ΅λλ€.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(new MemoryMemberRepository());
}
}
public class SingletonTest {
@Test
@DisplayName("μ€νλ§ μλ μμν DI 컨ν
μ΄λ")
void pureContainer() {
AppConfig appConfig = new AppConfig();
//μμ²μ΄ λ€μ΄μ¬λλ§λ€ κ°μ²΄λ₯Ό μμ±
MemberService memberService1 = appConfig.memberService();
MemberService memberService2 = appConfig.memberService();
//μ°Έμ‘°κ°μ΄ λ€λ₯Έ κ²μ νμΈ
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
assertThat(memberService1).isNotSameAs(memberService2);
}
}
memberService1
, memberService2
λ κ°μ ꡬνκ°μ²΄μ΄λ€. λ§μ½ μμ²μ΄ λ€μ΄μ¬λλ§λ€ κ°μ²΄λ₯Ό μμ±νκ² λλ€λ©΄ μ΄μ²λΌ κ°μ ꡬνκ°μ²΄λ€μ΄ κ³μ μΆκ°λ κ²μ΄λ€.@43e4ca52
, @137782a7
μ μμ±λ κ°μ²΄κ° μ°Έμ‘°νκ³ μλ μ£Όμκ°μ΄λ€. κ°μ΄ λ€λ₯΄λ€. μ΄ λ»μ λκ°μ ꡬνκ°μ²΄μ΄μ§λ§ μλ‘ λ€λ₯Έ κ³³μ μ°Έμ‘°νκ³ μλ€λ κ²μ΄λ€.public class SingletonService {
//1. static μμμ κ°μ²΄λ₯Ό λ± 1κ°λ§ μμ±ν΄λλ€.
private static final SingletonService instance = new SingletonService();
//2. public μΌλ‘ μ΄μ΄μ κ°μ²΄ μΈμ€ν°μ€κ° νμνλ©΄ μ΄ static λ©μλλ₯Ό ν΅ν΄μλ§ μ‘°ννλλ‘ νμ©νλ€.
public static SingletonService getInstance() {
return instance;
}
//3. μμ±μλ₯Ό private μΌλ‘ μ μΈν΄μ μΈλΆμμ new ν€μλλ₯Ό μ¬μ©ν κ°μ²΄ μμ±μ λͺ»νκ² λ§λλ€.
private SingletonService() {
}
}
public class SingletonTest {
@Test
@DisplayName("μ±κΈν€ ν¨ν΄μ μ μ©ν κ°μ²΄ μ¬μ©")
void singletonServiceTest() {
SingletonService instance1 = SingletonService.getInstance();
SingletonService instance2 = SingletonService.getInstance();
System.out.println("instance1 = " + instance1);
System.out.println("instance2 = " + instance2);
assertThat(instance1).isSameAs(instance2);
}
}
μ€νκ²°κ³Ό
μ€νκ²°κ³Ό κ°μ μ°Έμ‘°κ°(@9f8ea4d)μ κ°μ§κ³ μλ κ°μ²΄λ§ 리ν΄λμλ€.
μ±κΈν€ ν¨ν΄μ μ μ©νλ©΄ μμ²μ΄ μ¬ λ λ§λ€ κ°μ²΄λ₯Ό μμ±νλ κ²μ΄ μλλΌ, μ΄λ―Έ λ§λ€μ΄μ§ κ°μ²΄λ₯Ό 곡μ ν΄μ ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μλ€. νμ§λ§ μ±κΈν€ ν¨ν΄μ λ€μκ³Ό κ°μ μ λ§μ λ¬Έμ μ λ€μ κ°μ§κ³ μλ€.
νμ§λ§ μ°λ¦¬λ μ±κΈν€ λ¬Έμ μ λν κ³ λ―Όμ ν νμκ° μλ€. μ°λ¦¬κ° νμ΅ν μ€νλ§ λΉμ΄ λ°λ‘ μ±κΈν€μΌλ‘ κ΄λ¦¬λλ λΉμ΄λ€.
μ€νλ§ μ»¨ν μ΄λ λλΆμ μμ²μ΄ μ¬ λ λ§λ€ κ°μ²΄λ₯Ό μμ±νλ κ²μ΄ μλλΌ, μ΄λ―Έ λ§λ€μ΄μ§ κ°μ²΄λ₯Ό 곡μ ν΄μ ν¨μ¨μ μΌλ‘ μ¬μ¬μ©ν μ μλ€.
public class SingletonTest {
@Test
@DisplayName("μ€νλ§ μ»¨ν
μ΄λμ μ±κΈν€")
void springContainer() {
//μ€νλ§ μ»¨ν
μ΄λμμ λΉ μ‘°ννλλ‘ μμ
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
MemberService memberService2 = ac.getBean("memberService", MemberService.class);
//μ°Έμ‘°κ°μ΄ κ°μ κ²μ νμΈ
System.out.println("memberService1 = " + memberService1);
System.out.println("memberService2 = " + memberService2);
assertThat(memberService1).isSameAs(memberService2);
}
}
μ€νκ²°κ³Ό
κΈ°μ‘΄μ μ€νλ§ μ»¨ν μ΄λμμ μμ±λ λΉμ μ‘°νν΄λ³΄λ©΄, μ¬λ¬ κ°μ²΄λ₯Ό μμ±νκ³ μ£Όμ ν΄λ κ°μ κ°μ²΄κ° μ£Όμ λλ κ²μ νμΈν μ μλ€.
μ΄λ² ν μ€νΈ μ½λλ₯Ό μ΄μ©νμ¬ μ€νλ§ μ»¨ν μ΄λκ° μ±κΈν€ 컨ν μ΄λ μν μ νλμ§ μ§μ νμΈν μ μμλ€.
νμ§λ§ μ±κΈν€ λ°©μμ μ¬μ©ν λλ μ£Όμν΄μΌν μ¬νμ΄ μ‘΄μ¬νλ€.
μ μ§(stateful)
νκ² μ€κ³νλ©΄ μλλ€.무μν(stateless)
λ‘ μ€κ³ν΄μΌ νλ€. μ¦, κ°μ μ μ§νκ±°λ λ³κ²½ν΄μΌνλ νλκ° μμΌλ©΄ μλλ€.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;
}
}
this.price = price;
public class StatefulServiceTest {
@Test
@DisplayName("μνλ₯Ό μ μ§νλ μ±κΈν€ λ°©μμ λ¬Έμ μ ")
void statefulServiceSingleton() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean("statefulService", StatefulService.class);
StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);
//ThreadA : A μ¬μ©μκ° 10000μ μ£Όλ¬Έ
statefulService1.order("userA", 10000);
//ThreadB : B μ¬μ©μκ° 20000μ μ£Όλ¬Έ
statefulService2.order("userB", 20000);
//ThreadA : A μ¬μ©μκ° μ£Όλ¬Έ κΈμ‘ μ‘°ν
int price1 = statefulService1.getPrice();
System.out.println("price1 = " + price1);
assertThat(price1).isEqualTo(20000);
}
//ν
μ€νΈλ₯Ό μν μμ μ€μ
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
TestConfig
λ₯Ό μμ±νκ³ @Bean
νκ·Έλ‘ ApplicationContext
μ λ±λ‘νμλ€.StatefulService
λ₯Ό μ±κΈν€ κ°μ²΄λ‘ κ΄λ¦¬νλ€.StatefulService
λ κ°μ κ°μ²΄μ΄λ€. λ°λ‘ μμ±νμμ§λ§ κ°μ μ°Έμ‘°κ°μ ν΅νμ¬ price
νλμ μ κ·Όνλ€.
- μ΄ μ½λλ μ€νλ§ λΉμ λ±λ‘νλ
@Configuration
μ΄λ€.- μ¬κΈ°μ
memberRepository()
λ©μλλ 2λ² νΈμΆλκ³ μλ€.memberService
,orderService
λΉμ λ±λ‘ν λ κ°κ° νΈμΆμ΄ λλ©΄μnew MemoryMemberRepository()
μ½λλ₯Ό ν΅ν΄μ κ°μ κ°μ²΄λ₯Ό 2λ² λ§λ€ κ²μ΄λΌκ³ μκ°νκ² λλ€. κ³Όμ° μ¬μ€μΌκΉ?- μ€νλ§ μ»¨ν μ΄λλ λΉμ μ±κΈν€μΌλ‘ κ΄λ¦¬νλ€κ³ νλλ°... λΉμ λ±λ‘ν λ κ°μ κ°μ²΄λ₯Ό 2λ² νΈμΆν΄μ λ§λ€κ² λλ©΄ μ±κΈν€μ΄ μλκ±° μλμΌ? λΌκ³ μκ°ν΄ λ³Ό μ μλ€.
public class ConfigurationSingletonTest {
@Test
@DisplayName("μ€νλ§ λΉ λ±λ‘ μ μ€λ³΅μ¬λΆ νμΈ")
void configurationTest() {
//μ€νλ§ μ»¨ν
μ΄λ μ‘°ν
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
MemberRepository memberRepository1 = memberService.getMemberRepository();
MemberRepository memberRepository2 = orderService.getMemberRepository();
MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);
System.out.println("memberService -> memberRepository = " + memberRepository1);
System.out.println("orderService -> memberRepository = " + memberRepository2);
System.out.println("memberRepository -> memberRepository = " + memberRepository);
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
}
AppConfig
μμ 컨ν
μ΄λμ λΉμ λ±λ‘ν λ νΈμΆλλ new MemoryMemberRepository()
λ μ΄ 3λ²μ΄λ€.MemoryMemberRepository
κ°μ²΄λ₯Ό 3κ°λ₯Ό λ§λ€ κ²μ΄λ€. κ·Έλ λ€λ©΄ λͺ¨λ λ€λ₯Έ κ°μ²΄κ° μμ±λμ΄μΌ ν κ²μ΄λ€. μμμ΄ λ§μκΉ?@7824e97e
μ°Έμ‘°κ°μ΄ λͺ¨λ λκ°λ€. μ€νλ§ λΉμ λ±λ‘νλ©΄μ 3κ°μ μ°Έμ‘°κ°μ΄ λ€λ₯Ό κ²μ΄λΌ μμνμ§λ§ ν
μ€νΈ κ²°κ³Όλ λͺ¨λ κ°μ κ°μ²΄, μ¦ μ±κΈν€μΌλ‘ κ΄λ¦¬λκ³ μμμ νμΈνλ€.@Configuration
μ μ€μν μν μ λνμ¬ μμ보λλ‘ νκ² λ€.public class ConfigurationSingletonTest {
@Test
@DisplayName("μ€νλ§ λΉ ν΄λμ€ νμΈ")
void configurationDeepTest() {
//μ€νλ§ μ»¨ν
μ΄λ μ‘°ν
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
}
bean
μ μ‘°ννκ³ ν΄λμ€λͺ
μ μΆλ ₯νλ μ½λμ΄λ€.AppConfig
λ @Configuration
μΌλ‘ λ±λ‘λ ν΄λμ€μ΄λ€.bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$573a269b
$$EnhancerBySpringCGLIB$$573a269b
μ΄λΌλ μ΄μν λ΄μ©μ΄ μΆκ°λμλ€.CGLIB
λΌλ λ°μ΄νΈμ½λ μ‘°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν΄μ AppConfig ν΄λμ€λ₯Ό μμλ°μ μμμ λ€λ₯Έ ν΄λμ€λ₯Ό λ§λ€κ³ , κ·Έ λ€λ₯Έ ν΄λμ€λ₯Ό μ€νλ§ λΉμΌλ‘ λ±λ‘ν κ²μ΄λ€.@Bean
μ΄ λΆμ λ©μλλ§λ€ μ΄λ―Έ μ€νλ§ λΉμ΄ μ‘΄μ¬νλ©΄ μ‘΄μ¬νλ λΉμ λ°ννκ³ , μ€νλ§ λΉμ΄ μμΌλ©΄ μμ± ν΄μ μ€νλ§ λΉμΌλ‘ λ±λ‘νκ³ λ°ννλ μ½λκ° λμ μΌλ‘ λ§λ€μ΄μ§λ€.@Configuration
μ΄ μλ€λ©΄ μ΄λ»κ² λ κΉ?@Configuration
μ μ£Όμμ²λ¦¬νκ³ μ€νν ν
μ€νΈ κ²°κ³Όμ΄λ€.AppConfig.memberRepository
κ° λ°λ³΅μ μΌλ‘ μ€νλ κ²μ νμΈν μ μλ€. κ°μ²΄κ° 3κ° μμ±λμμ§λ§ μ±κΈν€μ 보μ₯νμ§ μλλ€.@Configuration
μ μ¬μ©νλ©΄ μ€νλ§ λΉμ μ±κΈν€μΌλ‘ 보μ₯νμ§λ§, μλ€λ©΄ μ€νλ§ λΉμ λ±λ‘λμ§λ§ μ±κΈν€μ 보μ₯νμ§ μλλ€.@Configuration
μ μ¬μ©νλλ‘ νμ.νμ΅μ λμμ΄ λμλ μλ£