์ธํ๋ฐ ๊น์ํ๋์ ์คํ๋ง ํต์ฌ ์๋ฆฌ - ๊ธฐ๋ณธํธ ๊ฐ์ ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์์ฑํ ๊ธ์ ๋๋ค.
1. ์ฑ๊ธํค ํจํด์ด๋?
์ฑ๊ธํค ํจํด์ด๋ ๊ฐ์ฒด์ ์ธ์คํด์ค๋ฅผ ๋ฑ 1๊ฐ๋ง ์์ฑํ๋ ๊ฒ์ ๋งํ๋ค. ์์ฑ์๋ฅผ ๋ช ๋ฒ ํธ์ถํ๋๋ผ๋ ์ธ์คํด์ค๋ ๋ฑ 1๊ฐ๋ง ์์ฑ๋๊ณ , ์ธ์คํด์ค ์์ฑ ์ดํ์ ํธ์ถ๋๋ ์์ฑ์๋ ์ด์ ์ ์์ฑํด๋ ์ธ์คํด์ค๋ฅผ ๋ฐํํด์ผ ํ๋ค.
์ฑ๊ธํค ํจํด์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ง๋ง, ์ฃผ๋ก ์๋์ ๊ฐ์ ๋ฐฉ๋ฒ์ด ๋ง์ด ์ฐ์ธ๋ค.
class Singleton {
private static final Singleton singleton = new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
singleton
ํ๋๋ static ๋ฉค๋ฒ๋ก ์ค์ ํ์ฌ ํ๋์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๋๋ก ์ค์ ํ๋ค.- ์์ฑ์๋ฅผ
private
๋ก ์ค์ ํ์ฌ ์ธ๋ถ์์ ์์ฑ์์ ์ ๊ทผํ๋ ๊ฒ์ ๋ง๋๋ค. getInstance()
๋ static ๋ฉ์๋๋ก ์ค์ ํ์ฌ, ์ธ์คํด์ค ์์ฑ ์์ด๋ ํธ์ถํ ์ ์๋๋ก ํ๋ค.
2. ์ฑ๊ธํค ํจํด์ ํ์์ฑ
๊ทธ๋ฐ๋ฐ ์ ๊ฐ์๊ธฐ ์ฑ๊ธํค ํจํด์ ๋ํ ์ด์ผ๊ธฐ๊ฐ ๋์ฌ๊น? ๋ฐ๋ก ์น ์ ํ๋ฆฌ์ผ์ด์
์ ํน์ฑ ๋๋ฌธ์ด๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ฌ๋ฌ ๊ณ ๊ฐ์ผ๋ก๋ถํฐ ์์ฒญ์ ๋ฐ๊ธฐ ๋๋ฌธ์, ๋์์ ์ฌ๋ฌ๊ฐ์ ์์ฒญ์ด ์ฌ ์๋ ์๋ค.
๋ง์ฝ ์ด๋น 1๋ง๊ฐ์ ์ฃผ๋ฌธ ์์ฒญ์ด ์ค๋ฉด, 1๋ง๊ฐ์ orderService
์ธ์คํด์ค๊ฐ ์์ฑ๋๋ค. ์ด๋ฐ ๋ฐฉ์์ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๊ฐ ์ฌํ๊ธฐ ๋๋ฌธ์ orderService
์ ์ฑ๊ธํค ํจํด์ ์ ์ฉํ์ฌ ์ธ์คํด์ค๋ ๋ฑ 1๊ฐ๋ง ์์ฑํ๊ณ , ํด๋ผ์ด์ธํธ๋ค์ด ์ด 1๊ฐ์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ์ฌ ์ฌ์ฉํ๋๋ก ๋ง๋๋ ๊ฒ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด ์ฑ๊ธํค ํจํด์ ์ด๋ป๊ฒ ์ ์ฉํด์ผ ํ ๊น? ์คํ๋ง์ด ์ด๋ฏธ ์ฑ๊ธํค ํจํด์ ์ ์ฉํด์ฃผ๊ณ ์๊ธฐ ๋๋ฌธ์, ์ฐ๋ฆฌ๋ ๋ฐ๋ก ์ฝ๋๋ฅผ ์์ ํ ํ์๊ฐ ์๋ค.
์คํ๋ง ์ปจํ ์ด๋๋ ์ฑ๊ธํค ํจํด์ ๋ฐ๋ก ์ ์ฉํ์ง ์์๋, ๊ธฐ๋ณธ์ ์ผ๋ก ์คํ๋ง ๋น์ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌํ๋ค. ๋น ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํด๋ ๋ค, ์กฐํ๊ฐ ๋ค์ด์ค๋ฉด ๊ทธ์ ํด๋นํ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ์์ด๋ค. ํ ์คํธ ์ฝ๋๋ฅผ ํตํด ํ์ธํด ๋ณด์.
ํ ์คํธ ์ฝ๋
@Test
void singletonTest() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService orderService1 = ac.getBean("orderService", OrderService.class);
OrderService orderService2 = ac.getBean("orderService", OrderService.class);
System.out.println("orderService1 = " + orderService1);
System.out.println("orderService2 = " + orderService2);
Assertions.assertThat(orderService1).isSameAs(orderService2);
์ถ๋ ฅ ๊ฒฐ๊ณผ
orderService1 = hello.core.order.OrderServiceImpl@3668d4
orderService2 = hello.core.order.OrderServiceImpl@3668d4
์ค์ ๋ก ๋น ์กฐํ ๋๋ง๋ค ๋์ผํ ์ธ์คํด์ค๋ฅผ ๋ฐํํด์ฃผ๋๊ฒ์ ๋ณผ ์ ์๋ค. ์ด๋ป๊ฒ ์ด๋ฐ ์ผ์ด ๊ฐ๋ฅํ ๊น?
3. @Configuration์ ์ญํ
@Configuration
public class AppConfig {
@Bean
public OrderService orderService() {
return new OrderServiceImpl(discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
return new FixDiscountPolicy();
}
}
์ง๋ ๊ธ์์ ์์ฑํ๋ ์ค์ ํ์ผ์ ๋ณด์. ์ฝ๋๋ง ๋ณด๋ฉด ์ฒ์์ orderService()
๋ฅผ ํธ์ถํ ๋ 1๋ฒ, ๊ทธ๋ฆฌ๊ณ discountPolicy
๋น์ ๋ฑ๋กํ ๋ 1๋ฒ ํด์ new FixDiscountPolicy()
๊ฐ 2๋ฒ ํธ์ถ๋์ด์ผ ํ ๊ฒ ๊ฐ๋ค.
@Configuration
public class AppConfig {
@Bean
public OrderService orderService() {
System.out.println("call orderService()");
return new OrderServiceImpl(discountPolicy());
}
@Bean
public DiscountPolicy discountPolicy() {
System.out.println("call discountPolicy()");
return new FixDiscountPolicy();
}
}
ํ์ง๋ง ์์ ๊ฐ์ด ํธ์ถ ๋ก๊ทธ๋ฅผ ๋จ๊ฒจ๋ณด๋ฉด,
call orderService()
call discountPolicy()
์ ๊ฐ์ด ๊ฐ๊ฐ 1๋ฒ์ฉ๋ง ํธ์ถ๋๋ค. ์ด๋ป๊ฒ ์ด๋ฐ ์ผ์ด ๊ฐ๋ฅํ ๊น? ๋ฐ๋ก @Configuration
๋๋ถ์ด๋ค.
์์ ์๋ฐ ์ฝ๋๋๋ก๋ฉด ๋ถ๋ช ํ 3๋ฒ ํธ์ถ๋์ด์ผ ํ๋ค. ์คํ๋ง์ด ์๋ฐ ์ฝ๋๋ฅผ ์์ ํ ๊ฑธ๊น?
์๋ฌด๋ฆฌ ์คํ๋ง์ด๋ผ๋ ์๋ฐ ์ฝ๋๊น์ง ์กฐ์ํ ์๋ ์๋ค. ๊ทธ ๋์ ์คํ๋ง์ ํด๋์ค์ ๋ฐ์ดํธ์ฝ๋๋ฅผ ์กฐ์ํ๋ CGLIB๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค. ์ฝ๋๋ฅผ ํตํด ์ง์ ํ์ธํด ๋ณด์.
ํ ์คํธ ์ฝ๋
@Test
void configurationDeep() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
์คํ๋ง ์ปจํ
์ด๋์ AppConfig
๋ฅผ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ ๋ค, ์ปจํ
์ด๋์์ ์กฐํํ๋ ์ฝ๋์ด๋ค.
์์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ์ฝ์์ bean = class hello.core.AppConfig
๊ฐ ์ถ๋ ฅ๋ ๊ฒ์ด๋ค.
๐กnew AnnotationConfigApplicationContext()์ ๋งค๊ฐ๋ณ์๋ก ๋๊ธฐ๋ ํด๋์ค๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๊ธฐ ๋๋ฌธ์, AppConfig.class๋ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๋ค.
์ถ๋ ฅ ๊ฒฐ๊ณผ
bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$ad8aea39
ํ์ง๋ง ์ค์ ๊ฒฐ๊ณผ๋ ์กฐ๊ธ ๋ค๋ฅด๋ค. hello.core.AppConfig
๋ค์ EnhancerBySpringCGLIB
๋ผ๋ ๋ฌธ์์ด์ด ๋ณด์ธ๋ค.
์ค์ AppConfig ํด๋์ค๊ฐ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋ ๊ฒ์ด ์๋๋ผ, ์คํ๋ง์ด CGLIB ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด AppConfig๋ฅผ ์์๋ฐ์ ์์ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , ๊ทธ ์์ ํด๋์ค๋ฅผ AppConfig ๋์ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋กํ๊ธฐ ๋๋ฌธ์ด๋ค.
์ด AppConfig@CGLIB ํด๋์ค๋ AppConfig์ ๋ฐ์ดํธ ์ฝ๋๋ฅผ ์กฐ์ํ์ฌ, discountPolicy()
์ ๊ตฌํ๋ถ๋ฅผ
(1) ๋ง์ฝ ์คํ๋ง ์ปจํ ์ด๋์ discountPolicy๋ผ๋ ๋น์ด ์์ผ๋ฉด ํด๋น ์ธ์คํด์ค๋ฅผ ๋ฐํํ๊ณ
(2) ์์ผ๋ฉด ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ์คํ๋ง ์ปจํ ์ด๋์ discountPolicy๋ผ๋ ์ด๋ฆ์ผ๋ก ๋ฑ๋กํ ๋ค ์ธ์คํด์ค๋ฅผ ๋ฐํํ๋ค.
์ ๋น์ทํ ๋ก์ง์ผ๋ก ๋ณํํ๋ค.
@Configuration
์ ๋
ธํ
์ด์
์ด ์ด ๊ณผ์ ๋ค์ ์งํํด์ฃผ๊ธฐ ๋๋ฌธ์, ์คํ๋ง ์ค์ ํ์ผ์ @Configuration
์ ์ถ๊ฐํ์ง ์์ผ๋ฉด ์ฑ๊ธํค์ด ๋ณด์ฅ๋์ง ์๋๋ค. AppConfig์์ @Configuration
์ ๋
ธํ
์ด์
์ ์ญ์ ํ ๋ค, ์๋์ ๊ฐ์ ํ
์คํธ ์ฝ๋๋ฅผ ์คํํด๋ณด์.
ํ ์คํธ ์ฝ๋
// OrderServiceImpl ํด๋์ค์ ์๋ ์ฝ๋ ์ถ๊ฐ
// public DiscountPolicy getDiscountPolicy() { return discountPolicy; }
@Test
void configurationTest2() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);
DiscountPolicy discountPolicy1 = ac.getBean("discountPolicy", FixDiscountPolicy.class);
DiscountPolicy discountPolicy2 = orderService.getDiscountPolicy();
System.out.println("discountPolicy1 = " + discountPolicy1);
System.out.println("discountPolicy2 = " + discountPolicy2);
Assertions.assertThat(discountPolicy1).isSameAs(discountPolicy2);
}
์ถ๋ ฅ ๊ฒฐ๊ณผ
call orderService()
call discountPolicy()
call discountPolicy()
discountPolicy1 = hello.core.discount.FixDiscountPolicy@34f22f9d
discountPolicy2 = hello.core.discount.FixDiscountPolicy@3d1848cc
discountPolicy
๋ ๋น์ผ๋ก ๋ฑ๋ก๋๊ธด ํ์ง๋ง, ์คํ๋ง ์ปจํ
์ด๋์ ๋น์ผ๋ก ๋ฑ๋ก๋ ์ธ์คํด์ค์ orderService
์ ์ฃผ์
๋ ์ธ์คํด์ค๊ฐ ๋ค๋ฅด๋ค๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
4. ์ฑ๊ธํค ํจํด์ ์ฃผ์์
์ง๊ธ๊น์ง ์ฑ๊ธํค ํจํด์ ์๋ฏธ์ ์คํ๋ง์์ ์ฑ๊ธํค ํจํด์ ์ ์งํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์๋ค. ์ด๋ฐ ์ฑ๊ธํค ํจํด์ ์ฌ์ฉํ๋ ค๋ฉด ์ ์ํด์ผ ํ๋ ์ ์ด ์๋ค.
์ฑ๊ธํค ๋ฐฉ์์ ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ํ๋์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ์ฌ ์ฌ์ฉํ๋ค. ๋๋ฌธ์ ์ฑ๊ธํค์ผ๋ก ์ค๊ณํ ๊ฐ์ฒด๋ ๊ณต์ ํ๋๊ฐ ์๋ ๋ฌด์ํ(stateless)๋ก ์ค๊ณํด์ผ ํ๋ค. ์กฐ๊ธ ๋ ์ฝ๊ฒ ๋งํ๋ฉด, ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ฒด์ ํ๋๋ฅผ ๋ณ๊ฒฝํ ์ ์๋๋ก ์ค๊ณํ๋ฉด ์๋๋ค๋ ์๋ฏธ์ด๋ค. ํด๋ผ์ด์ธํธ๋ ๊ฐ๊ธ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํด์ผ ํ๋ฉฐ, ๋ง์ฝ ํด๋ผ์ด์ธํธ๋ง๋ค ์ค์ ํด์ผ ํ๋ ๊ฐ์ด ์๋ค๋ฉด ๊ณต์ ๋๋ ํ๋ ๋์ ๋งค๊ฐ๋ณ์ ๋ฑ์ ์ด์ฉํด์ผ ํ๋ค.
๊ฐ๋จํ๊ฒ ์ฝ๋๋ก ์ดํด๋ณด์.
statefulํ ์ฝ๋
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;
}
}
์์ ๊ฐ์ด ์ํ๋ฅผ ์ ์งํ๋ ์๋น์ค ๊ฐ์ฒด๋ฅผ ์ค๊ณํ๋ค.
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 ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ
int price = statefulService1.getPrice();
System.out.println("price = " + price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
์ถ๋ ฅ ๊ฒฐ๊ณผ
price = 20000
๊ทธ๋ฆฌ๊ณ ํ
์คํธ ์ฝ๋๋ฅผ ๋๋ ค๋ณด๋ฉด, ์ฌ์ฉ์ A๊ฐ ์ฌ์ฉํ๋ statefulService1
์ธ์คํด์ค์ price
๊ฐ์ด 20000์ผ๋ก ์ค์ ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฌ์ฉ์ A ์ ์ฅ์์๋ ๋ง์์ ์ฃผ๋ฌธํ๋๋ฐ 2๋ง์์ ์ฒญ๊ตฌ๋ฐ์ ์ํฉ์ด๋ค. ์ด๋ ์ฌ์ฉ์ A์ B๊ฐ StatefulService์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ์ฌ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค.
(1) ์ฌ์ฉ์ A๊ฐ statefulService์ price๋ฅผ 10000์ผ๋ก ์ค์
(2) ์ฌ์ฉ์ B๊ฐ statefulService์ price๋ฅผ 20000์ผ๋ก ์ค์
(3) ์ฌ์ฉ์ A๊ฐ statefulService์ price๋ฅผ ์กฐํ -> 20000 ๋ฐํ!
์์ ํ ์ฝ๋
public class StatefulService {
public int order(String name, int price) {
System.out.println("name = " + name + " price = " + price);
return price;
}
}
price
๋ฅผ ํ๋๊ฐ ์๋ ๋ฉ์๋์ ๋งค๊ฐ๋ณ์๋ก ๋๊ธด ๋ค ๋ฐ๋ก ์ถ๋ ฅํ๋ฉด, ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
'๐๐ฉ๐ซ๐ข๐ง๐ > ๐๐๐ฌ๐ข๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์กด๊ด๊ณ ์ฃผ์ ๋ฐฉ๋ฒ (0) | 2023.09.12 |
---|---|
์ปดํฌ๋ํธ ์ค์บ (0) | 2023.09.02 |
์คํ๋ง ์ปจํ ์ด๋๋? (0) | 2023.09.02 |
์ ์ด์ ์ญ์ (IoC)๊ณผ ์์กด๊ด๊ณ ์ฃผ์ (DI)์ด๋? (0) | 2023.08.28 |
๊ฐ์ฒด ์งํฅ ์ค๊ณ์ 5๊ฐ์ง ์์น (0) | 2023.08.28 |