์คํ๋ง ํต์ฌ ์๋ฆฌ์ ๊ฐ์ ๋ด์ฉ์ ์ ๋ฆฌํ ํฌ์คํ ์ ๋๋ค.
์ฑ๊ธํค ํจํด
ํด๋์ค์ ์ธ์คํด์ค๊ฐ 1๊ฐ๋ง ์์ฑ๋๋ ๊ฒ์ ๋ณด์ฅํ๋ ๋์์ธ ํจํด์ด๋ค.
์คํ๋ง์ด ์๋ ์์ํ DI(Dependency Injection) ์ปจํ ์ด๋๋ฅผ ์ด์ฉํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
DI ์ปจํ ์ด๋์ธ AppConfig๋ ์๋ก์ด ์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๋ฐํํ๋๋ฐ, ํธ๋ํฝ์ด ์ฆ๊ฐํ ์๋ก ์์ฑ๋๋ ๊ฐ์ฒด๊ฐ ๋ง์์ง์ ๋ฐ๋ผ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ ์ฌํด์ง๋ค๋ ๋จ์ ์ด ์กด์ฌํ๋ค.
์ด๋ฌํ ํด๊ฒฐ๋ฐฉ์์ผ๋ก์จ ๊ฐ์ ๊ฐ์ฒด๋ ๋ฑ 1๊ฐ๋ง ์์ฑ๋๋๋ก ํ์ฌ ๊ฐ์ฒด๋ฅผ ๊ณต์ ํ๊ฒ๋ ์ค๊ณํ๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ ์ ์๋๋ฐ, ํด๋น ๋ฐฉ๋ฒ์ด ์ฑ๊ธํค ํจํด์ ์ด์ฉํ๋ ๊ฒ์ด๋ค.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
private SingletonService() {}
public static SingletonService getInstance() {
return instance;
}
public void logic() {
System.out.println("์ฑ๊ธํค ๊ฐ์ฒด ๋ก์ง ํธ์ถ");
}
}
์์ ์ฝ๋๋ ์ฑ๊ธํค ํจํด์ ์ ์ฉํ ์์ ์ฝ๋์ด๋ค.
์ฐ์ static ์์ญ์ instance๋ผ๋ ๊ฐ์ฒด๋ฅผ ํ๋ ์์ฑํ๊ฒ ๋๋๋ฐ, ํด๋น ๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ ๋ฐ๋์ getInstance๋ฅผ ์ด์ฉํด์ผ ํ๊ธฐ ๋๋ฌธ์ ํญ์ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ๋ฐํํ๊ฒ ๋๋ค.
๋ํ ๋ฑ 1๊ฐ์ ๊ฐ์ฒด ์ธ์คํด์ค๋ง ์กด์ฌํด์ผ ํ๋ฏ๋ก, ์์ฑ์๋ฅผ private์ผ๋ก ์ ์ธํจ์ผ๋ก์จ ์ธ๋ถ์์ ์๋ก์ด ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ์์ฑํ ์ ์๋ ๊ฐ๋ฅ์ฑ์ ์ฐจ๋จํ๊ณ ์๋ค.
์ฑ๊ธํค ํจํด์ ์ ์ฉํ๋ฉด ๊ณ ๊ฐ์ ์์ฒญ์ด ์ฌ ๋๋ง๋ค ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์๋, ์ด๋ฏธ ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ฅผ ๊ณต์ ํด์ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค๋ ์ฅ์ ์ด ์์ง๋ง ์ ๋ง์ ๋ฌธ์ ์ ๋ํ ์กด์ฌํ๋ค.
1. ์ฑ๊ธํค ํจํด์ ๊ตฌํํ๊ธฐ ์ํ ์ถ๊ฐ์ ์ธ ์ฝ๋ ์์ฑ์ด ์๋ฐ๋๋ค.
2. ์์กด๊ด๊ณ์ ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กดํ๋ฏ๋ก DIP๋ฅผ ์๋ฐํ๋ค.
3. ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กดํ๊ธฐ ๋๋ฌธ์ OCP๋ฅผ ์๋ฐํ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
4. ํ ์คํธํ๊ธฐ ์ด๋ ต๋ค.
5. ์์ ํด๋์ค๋ฅผ ๋ง๋ค๊ธฐ ์ด๋ ต๋ค.
์ด๋ฌํ ๋ฌธ์ ์ ๋ค๋ก ์ธํ์ฌ ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋ค๋ ๋จ์ ์ด ์กด์ฌํ๋ค.
์คํ๋ง ์ปจํ ์ด๋
์คํ๋ง ์ปจํ ์ด๋๋ ๊ฐ๋ฐ์๊ฐ ์ฑ๊ธํค ํจํด์ ์ ์ฉํ์ง ์์๋ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ํ๋๋ง ์์ฑํ์ฌ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์, ์ฑ๊ธํค ํจํด์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ฉด์ ๊ฐ์ฒด๋ฅผ ์ฑ๊ธํค์ผ๋ก ์ ์งํ ์ ์๋ค.
(์ฑ๊ธํค ํจํด์ ๊ตฌํํ๊ธฐ ์ํ ๋ถ๊ฐ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ ํ์๊ฐ ์๊ณ , DIP/OCP/ํ ์คํธ/private ์์ฑ์๋ก๋ถํฐ ์์ ๋กญ๊ฒ ์ฑ๊ธํค์ ์ฌ์ฉํ ์ ์๋ค.)
์คํ๋ง ์ปจํ ์ด๋ ๋๋ถ์ ๊ณ ๊ฐ์ ์์ฒญ์ด ์ฌ ๋๋ง๋ค ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด ์๋, ์ด๋ฏธ ๋ง๋ค์ด์ง ๊ฐ์ฒด๋ฅผ ๊ณต์ ํด์ ํจ์จ์ ์ผ๋ก ์ฌ์ฌ์ฉํ ์ ์๋ค.
์ฑ๊ธํค ๋ฐฉ์์ ์ฃผ์์
๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ํ๋๋ง ์์ฑํด์ ๊ณต์ ํ๋ ์ฑ๊ธํค ๋ฐฉ์์ ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ํ๋์ ๊ฐ์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๊ธํค ๊ฐ์ฒด๋ ์ํ๋ฅผ statelessํ๊ฒ ์ค๊ณํด์ผํ๋๋ฐ, ์ด๋ฅผ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ์ฌํญ์ ๊ณ ๋ คํด์ผ ํ๋ค.
1. ํน์ ํด๋ผ์ด์ธํธ์ ์์กด์ ์ธ ํ๋๊ฐ ์์ด์๋ ์๋๋ค.
2. ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํ๋๊ฐ ์์ผ๋ฉด ์๋๋ค.
3. ๊ฐ๊ธ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํด์ผ ํ๋ค.
4. ํ๋๊ฐ ์๋ ์๋ฐ์์ ๊ณต์ ๋์ง ์๋ ์ง์ญ๋ณ์/ํ๋ผ๋ฏธํฐ/ThreadLocal ๋ฑ์ ์ฌ์ฉํด์ผ ํ๋ค.
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;
}
}
public class StatefulServiceTest {
@Test
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 ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ -> 10000์์ด ์๋ 20000์ ์ถ๋ ฅ
int price = statefulService1.getPrice();
assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
์ค์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ง๋ ์์์ง๋ง ์ค๋ ๋A๊ฐ ์ฌ์ฉ์A ์ฝ๋๋ฅผ ํธ์ถํ๊ณ , ์ค๋ ๋B๊ฐ ์ฌ์ฉ์B ์ฝ๋๋ฅผ ํธ์ถํ๋ค๊ณ ๊ฐ์ ํด๋ณด์. StatefulService์ price๋ ๊ณต์ ๋๋ ํ๋์ด์ง๋ง ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ๊ณ ์์ด ์๋์๋ ๋ค๋ฅธ ๊ฐ์ด ๋์จ๋ค.
๋ฐ๋ผ์ ์คํ๋ง ๋น์ ํญ์ statelessํ๊ฒ ์ค๊ณํด์ผ ํ๋ค.
@Configuration๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์
@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();
}
}
memberService ๋น์ ๋ง๋๋ ์ฝ๋์ orderService ๋น์ ๋ง๋๋ ์ฝ๋์์ ๋์ผํ๊ฒ memberRepository()๋ฅผ ํธ์ถํ๊ณ ์๋๋ฐ, ์ด๋ ๊ฒฐ๊ณผ์ ์ผ๋ก ๊ฐ๊ธฐ ๋ค๋ฅธ 2๊ฐ์ MemoryMemberRepository๊ฐ ์์ฑ๋๋ฉด์ ์ฑ๊ธํค์ด ๊นจ์ง๋ ๊ฒ์ฒ๋ผ ๋ณด์ธ๋ค.
์คํ๋ง ์ปจํ
์ด๋๋ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ๊น?
์ฐ๋ฆฌ์ ์์๋๋ก๋ผ๋ฉด memberRepository()๋ ์ด 3๋ฒ์ด ํธ์ถ๋์ด์ผ ํ๋ค.
1. ์คํ๋ง ์ปจํ
์ด๋๊ฐ ์คํ๋ง ๋น์ ๋ฑ๋กํ๊ธฐ ์ํด @Bean์ด ๋ถ์ด์๋ memberRepository() ํธ์ถ
2. memberService() ๋ก์ง์์ memberRepository() ํธ์ถ
3. orderService() ๋ก์ง์์ memberRepository() ํธ์ถ
๊ทธ๋ฐ๋ฐ ์ค์ ๋ก ํธ์ถ ๋ก๊ทธ๋ฅผ ์ฐ์ด๋ณด๋ฉด ์ด 1๋ฒ๋ง ํธ์ถ๋๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ ์คํ๋ง ๋น์ด ์ฑ๊ธํค์ด ๋๋๋ก ๋ณด์ฅํด์ฃผ์ด์ผ ํ๋๋ฐ, ์คํ๋ง์ด ์๋ฐ ์ฝ๋๊น์ง ์กฐ์ํ๊ธฐ์๋ ํ๊ณ๊ฐ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ํด๋์ค์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
์ด๋ @Configuration์ ์ ์ฉํจ์ผ๋ก์จ ๊ฐ๋ฅํด์ง๋ค.
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
AnnotationConfigApplicationContext์ ํ๋ผ๋ฏธํฐ๋ก ๋๊ธด ๊ฐ์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์ AppConfig๋ ์คํ๋ง ๋น์ด ๋๋ค.
๋ง์ฝ AppConfig๊ฐ ์์ํ ํด๋์ค๋ผ๋ฉด class hello.core.AppConfig์ ๊ฐ์ด ์ถ๋ ฅ๋์ด์ผ ํ์ง๋ง, ์ค์ ๋ก๋ ํด๋์ค๋ช
์ CGLIB๊ฐ ๋ถ์ ์ฑ๋ก ์ถ๋ ฅ๋๋ค.
์ฆ, ์ง์ ๋ง๋ ํด๋์ค๊ฐ ์๋ ์คํ๋ง์ด CGLIB๋ผ๋ ๋ฐ์ดํธ์ฝ๋ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด AppConfig ํด๋์ค๋ฅผ ์์๋ฐ๋ ์์์ ๋ค๋ฅธ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ ํด๋น ํด๋์ค๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ ๊ฒ์ด๋ค.
๊ทธ ์์์ ๋ค๋ฅธ ํด๋์ค๊ฐ ์ฑ๊ธํค์ด ๋ณด์ฅ๋๋๋ก ํด์ฃผ๋ ๊ฒ์ธ๋ฐ, CGLIB์ ๋ด๋ถ ๊ธฐ์ ์ ๋ณต์กํ์ง๋ง ์๋ฆฌ๋ง ๊ฐ๋จํ๊ฒ ์ดํด๋ณธ๋ค๋ฉด ์๋ง๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํด์ ์์ฑ๋์ด ์์ ๊ฒ์ด๋ค.
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository๊ฐ ์ด๋ฏธ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก๋์ด ์๋ค) {
return ์คํ๋ง ์ปจํ
์ด๋์์ ์ฐพ์ ๋ค ๋ฐํ;
} else {
๊ธฐ์กด ๋ก์ง์ ํธ์ถํด์ MemoryMemberRepository๋ฅผ ์์ฑํ๊ณ ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก;
return ๋ฐํ;
}
}
๋ง์ฝ @Configuration์ ์ ์ฉํ์ง ์๊ณ @Bean๋ง ์ ์ฉํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
@Configuration์ ์ญ์ ํ ๋ค ์คํํ๋ฉด CGLIB ๊ธฐ์ ์์ด ์์ํ AppConfig๋ก ์คํ๋ง ๋น์ ๋ฑ๋ก๋๊ณ , ๊ฐ๊ธฐ ๋ค๋ฅธ MemoryMemberRepository ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก๋ @Bean๋ง ์ฌ์ฉํด๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์ง๋ง, ์ฑ๊ธํค์ ๋ณด์ฅํ์ง๋ ์๋๋ค.
๋ฐ๋ผ์ ์คํ๋ง ์ค์ ์ ๋ณด๋ @Configuration์ ์ด์ฉํด์ฃผ๋ฉด ๋๋ค.
'Language & Framework > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์คํ๋ง ํต์ฌ ์๋ฆฌ] ์์กด๊ด๊ณ ์๋ ์ฃผ์ (2) (0) | 2022.12.21 |
---|---|
[์คํ๋ง ํต์ฌ ์๋ฆฌ] ์์กด๊ด๊ณ ์๋ ์ฃผ์ (1) (0) | 2022.12.21 |
[์คํ๋ง ํต์ฌ ์๋ฆฌ] ์คํ๋ง ์ปจํ ์ด๋์ ์คํ๋ง ๋น (0) | 2022.11.14 |
[์คํ๋ง ํต์ฌ ์๋ฆฌ] ์์ ์ค๊ณ ๋ฐ ๊ฐ์ฒด ์งํฅ ์๋ฆฌ ์ ์ฉ (0) | 2022.11.14 |
[์คํ๋ง ํต์ฌ ์๋ฆฌ] ๊ฐ์ฒด ์งํฅ ์ค๊ณ์ ์คํ๋ง (0) | 2022.11.14 |