Singleton Container
์น ์ ํ๋ฆฌ์ผ์ด์ & ์ฑ๊ธํค
์ผ๋ฐ์ ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ ๊ณ ๊ฐ์ด ๋์์ ์์ฒญ์ ํ๋ค!
![](https://blog.kakaocdn.net/dn/uxy78/btrU1NFLY1W/9X4D4CedOKGWmfLcl6PiK1/img.png)
์คํ๋ง ์๋ ์์ํ DI์ปจํ ์ด๋
public class SingletonTest {
@Test
@DisplayName("์คํ๋ง ์๋ ์์ํ DI์ปจํ
์ด๋")
void pureContainer() {
AppConfig appConfig = new AppConfig();
// 1. ์กฐํ: ํธ์ถ ํ ๋๋ง๋ค ๊ฐ์ฒด ์์ฑ
MemberService memberService1 = appConfig.memberService();
// 2. ์กฐํ: ํธ์ถ ํ ๋๋ง๋ค ๊ฐ์ฒด ์์ฑ
MemberService memberService2 = appConfig.memberService();
// ์ฐธ์กฐ๊ฐ์ด ๋ค๋ฅด๋ค
// System.out.println("memberService1 = " + memberService1);
// System.out.println("memberService2 = " + memberService2);
Assertions.assertThat(memberService1).isNotSameAs(memberService2);
}
}
์์ ๊ฐ์ ๋ฐฉ์์ผ๋ก๋ ์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ฒ ๋๋ค -> ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น!
๋ฐ๋ผ์ ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ์์ด ์ฑ๊ธํค ํจํด!
โ 1๊ฐ์ ๊ฐ์ฒด๋ง ์์ฑ๋๊ณ ๊ณต์ ํ๋๋ก ์ค๊ณ
์ฑ๊ธํค ํจํด
โ ์ฑ๊ธํค ํจํด(Singleton Pattern): ํด๋์ค์ ์ธ์คํด์ค๊ฐ ๋ฑ 1๊ฐ๋ง ์์ฑ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ๋์์ธ ํจํด
private ์์ฑ์๋ฅผ ์ด์ฉํด ์ธ๋ถ์์ ์์๋ก new ํค์๋๋ฅผ ์ฌ์ฉํด ๋ ๊ฐ ์ด์์ ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ์์ฑ๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ค
์ฑ๊ธํค ํจํด์ ์ ์ฉํ ์ฝ๋
package hello.core.singleton;
public class SingletonService {
// 1. static ์์ญ์ 1๊ฐ์ ๊ฐ์ฒด๋ง์ ์์ฑ
private static final SingletonService instance = new SingletonService();
// 2. ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ํ์ํ๋ฉด ํด๋น public static ๋ฉ์๋๋ฅผ ํตํด์๋ง ์กฐํ ๊ฐ๋ฅ
public static SingletonService getInstance() {
return instance;
}
// 3. private ์์ฑ์
private SingletonService() {
}
public void logic() {
System.out.println("์ฑ๊ธํค ๊ฐ์ฒด ๋ก์ง ํธ์ถ");
}
}
- static ์์ญ์ ํ ๊ฐ์ ๊ฐ์ฒด instance๋ง์ ์์ฑํด์ ์ฌ๋ ค๋๋ค.
- ํด๋น ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ํ์ํ๋ฉด ์ค์ง
getInstance()
๋ฉ์๋๋ฅผ ํตํด์๋ง ์กฐํ ๊ฐ๋ฅ(ํญ์ ๊ฐ์ ์ธ์คํด์ค ๋ฐํ) - ์์ฑ์๋ฅผ private์ผ๋ก ๋ง์ ์ธ๋ถ์์ ์๋ก์ด ๊ฐ์ฒด ์์ฑ ๋ฐฉ์ง
์ฑ๊ธํค ํจํด ํ ์คํธ ์ฝ๋
@Test
@DisplayName("์ฑ๊ธํค ํจํด์ ์ ์ฉํ ๊ฐ์ฒด ์ฌ์ฉ")
void singletonServiceTest() {
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
//์ฐธ์กฐ๊ฐ์ด ๊ฐ์ ๊ฒ์ ํ์ธ
System.out.println("singletonService1 = " + singletonService1);
System.out.println("singletonService2 = " + singletonService2);
// same: ๊ฐ์ฒด ๋น๊ต (==)
// equal: equals ๋ฉ์๋
Assertions.assertThat(singletonService1).isSameAs(singletonService2);
}
![](https://blog.kakaocdn.net/dn/dhatk6/btrUYqq09Om/EbwRhyBWtGSNVmJM3AmXS1/img.png)
๊ฐ์ ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ๋ฐํ๋๋ค.
์ฑ๊ธํค ํจํด์ ๋จ์
์ฑ๊ธํค ํจํด์ ๊ตฌํํ๋ ์ฝ๋ ์์ฒด๊ฐ ๋ง๋ค
ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กดํ๊ฒ ๋๋ค (DIP, OCP ์๋ฐ)
ํ ์คํธํ๊ธฐ๊ฐ ์ด๋ ค์
๋ด๋ถ ์์ฑ ๋ณ๊ฒฝ or ์ด๊ธฐํ ์ด๋ ค์
โ ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋ค
์ฑ๊ธํค ์ปจํ ์ด๋
์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํด์ ์ฑ๊ธํค ํจํด์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ฉด์ ์ฑ๊ธํค ํจํด์ ์ ์ฉํ ์ ์๋ค.
์ฑ๊ธํค ์ปจํ ์ด๋
โ ์คํ๋ง ์ปจํ ์ด๋๋ ์ฑ๊ธํค ํจํด์ ์ ์ฉํ์ง ์์๋ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์์ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌํ๋ค
์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ: ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ
์ฑ๊ธํค ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ๋ฉด
- ์ฑ๊ธํค ํจํด์ ์ํ ์ฝ๋๋ฅผ ๋ฐ๋ก ์์ฑํ์ง ์์๋ ๋๋ค
- DIP, OCP, ํ ์คํธ, private ์์ฑ์ ๋ฑ ์ฑ๊ธํค ํจํด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์ek.
์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํ ํ ์คํธ ์ฝ๋
@Test
@DisplayName("์คํ๋ง ์ปจํ
์ด๋์ ์ฑ๊ธํค")
void springContainter() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
// 1. ์กฐํ: ํธ์ถ ํ ๋๋ง๋ค ๊ฐ์ฒด ์์ฑ
MemberService memberService1 = ac.getBean("memberService", MemberService.class);
// 2. ์กฐํ: ํธ์ถ ํ ๋๋ง๋ค ๊ฐ์ฒด ์์ฑ
MemberService memberService2 = ac.getBean("memberService", MemberService.class);
// ์ฐธ์กฐ๊ฐ์ด ๊ฐ๋ค
// System.out.println("memberService1 = " + memberService1);
// System.out.println("memberService2 = " + memberService2);
Assertions.assertThat(memberService1).isSameAs(memberService2);
}
์ฑ๊ธํค ์ปจํ ์ด๋ ์ ์ฉ ํ
![](https://blog.kakaocdn.net/dn/nOlt5/btrU6YfhW0p/ywkfG42RYn9wxIATCoDXr1/img.png)
์คํ๋ง ์ปจํ ์ด๋๋ฅผ ํ์ฉํ์ฌ ํ๋์ ๊ฐ์ฒด๋ฅผ ๊ณต์ ํด์ ํจ์จ์ ์ผ๋ก ์ฌ์ฌ์ฉ ํ ์ ์๋ค.
- ์ฐธ๊ณ : ์คํ๋ง์ ์ฑ๊ธํค ๋ฐฉ์ ์ธ์ ๋ฐฉ์์ผ๋ก๋ ๋น์ ๋ฑ๋กํ ์ ์๋ค (๋น์ค์ฝํ)
์ฑ๊ธํค ๋ฐฉ์์ ์ฃผ์์
โ ์ฑ๊ธํค ๋ฐฉ์์ ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ํ๋์ ๋์ผํ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ์ํ๋ฅผ ์ ์ง(stateful)ํ๊ฒ ์ค๊ณ ํ๋ฉด ์๋๋ค.
โ ์ฑ๊ธํค์ ๋ฌด์ํ(Stateless)๋ก ์ค๊ณํด์ผ ํ๋ค
- ํน์ ํด๋ผ์ด์ธํธ์ ์์กด์ ์ธ ํ๋ x
- ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํ๋ x
- (๊ฐ๊ธ์ ) ์ฝ๊ธฐ๋ง ๊ฐ๋ฅ
- ํ๋ ๋์ ์๋ฐ์์ ๊ณต์ ๋์ง ์๋ ์ง์ญ๋ณ์, ํ๋ผ๋ฏธํฐ, ThreaLocal ๋ฑ ์ฌ์ฉ
Stateful ์ฑ๊ธํค์ ๋ฌธ์ ์
package hello.core.singleton;
public class StatefulService {
private int price; // ์ํ๋ฅผ ์ ์ง(Stateful)ํ๋ ํ๋
public void order (String name, int price) {
System.out.println("name = " + name + " price = " + price);
this.price = price; // ์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
}
public int getPrice() {
return price;
}
}
class StatefulServiceTest {
@Test
void statefulServiceSingleton() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean(StatefulService.class);
StatefulService statefulService2 = ac.getBean(StatefulService.class);
// Thread A: A์ฌ์ฉ์ 10000์ ์ฃผ๋ฌธ
statefulService1.order("userA", 10000);
// Thread B: B์ฌ์ฉ์ 20000์ ์ฃผ๋ฌธ
statefulService2.order("userB", 20000);
// Thread A: ์ฌ์ฉ์ A ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ
int price = statefulService1.getPrice();
System.out.println("price = " + price);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
![](https://blog.kakaocdn.net/dn/c7qfbt/btrU8FT5tu9/Ol3B0NbE1DF3YcyNyAgr2k/img.png)
price
ํ๋๊ฐ ๊ณต์ ๋์ด ๊ฐ์ด ๋ฎ์ด์์์ง๋ค!
@Configuration
๊ณผ ์ฑ๊ธํค
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(), new FixDiscountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public DiscountPolicy discountPolicy() {
return new RateDiscountPolicy();
}
}
memberService -> memberRepository()
orderService -> memberRepository()
์์ ๊ฐ์ ์ฝ๋์์ MemoryMemborRepository๋ ๋ช ๋ฒ ํธ์ถ๋ ๊ฒ์ธ๊ฐ?
@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);
//๋ชจ๋ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์ฐธ๊ณ ํ๊ณ ์๋ค.
System.out.println("memberService -> memberRepository = " + memberService.getMemberRepository());
System.out.println("orderService -> memberRepository = " + orderService.getMemberRepository());
System.out.println("memberRepository = " + memberRepository);
//๋ชจ๋ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ์ฐธ๊ณ ํ๊ณ ์๋ค.
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
}
// ํ
์คํธ ๊ฒฐ๊ณผ
memberService -> memberRepository = hello.core.member.MemoryMemberRepository@56e8b606
orderService -> memberRepository = hello.core.member.MemoryMemberRepository@56e8b606
memberRepository = hello.core.member.MemoryMemberRepository@56e8b606
2๋ฒ์ผ ๊ฒ ๊ฐ์ง๋ง ์ค์ ๋ก ์กฐํํด๋ณด๋ฉด 1๋ฒ๋ง ํธ์ถ๋๋ค(๋์ผํ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐ)
@Configuration
๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์์ ๋ง๋ฒ
์์ ๊ฐ์ ์ํฉ์์ ์คํ๋ง์ ํด๋์ค์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ํ ๋ฒ๋ง ํธ์ถ๋๋๋ก ํ๋ค
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
//AppConfig๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๋ค.
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
//์ถ๋ ฅ: bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
}
AppConfig$$EnhancerBySpringCGLIB$$bd479d70
???
![](https://blog.kakaocdn.net/dn/A0Bbe/btrU1Oq8ckC/llEkxqUTpmPuRHobsSlkT0/img.png)
์คํ๋ง์ด CGLIB๋ผ๋ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ AppConfig
ํด๋์ค๋ฅผ ์์๋ฐ์ ์์์ ๋ค๋ฅธ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ๊ทธ ๋ค๋ฅธ ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๋ค
@Bean๋ง ์ฌ์ฉํด๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋์ง๋ง, ์ฑ๊ธํค์ ๋ณด์ฅํ์ง ์๋๋ค
โ ์คํ๋ง ์ค์ ์ ๋ณด๋ ํญ์ @Configuration
์ฌ์ฉ
'โญ Personal_Study > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์กด๊ด๊ณ ์๋ ์ฃผ์ (1) | 2023.01.09 |
---|---|
ComponentScan (0) | 2023.01.07 |
์คํ๋ง ์ปจํ ์ด๋ & Bean ์กฐํ (0) | 2023.01.05 |
์ ์ด์ ์ญ์ (IoC) & ์์กด์ฑ ์ฃผ์ (DI) (1) | 2023.01.01 |
SOLID (์ข์ ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ 5๊ฐ์ง ์์น) (1) | 2022.12.31 |
๋๊ธ