์ฑ๊ธํค ํจํด
๊ฐ์ฒด์ ์ธ์คํด์ค๊ฐ ๋ฑ 1๊ฐ๋ง ์์ฑ๋์ด ๊ณต์ ๋๋ ํจํด์ ์๋ฏธํ๋ค.
์ธ์คํด์ค๊ฐ ํ๋์ฉ๋ง ์์ฑ๋๋ฏ๋ก ํจ์จ์ ์ธ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
๊ฐ์ฒด๊ฐ ํธ์ถ๋์ ๋, ์ด๋ฏธ ๋ง๋ค์ด๋์ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํจ์ผ๋ก์จ ํจ์จ์ ์ธ ์ฌ์ฌ์ฉ ๋ํ ๊ฐ๋ฅํ๋ค.
๊ทธ๋ฌ๋ ์ฑ๊ธํค ํจํด์ โ ๊ตฌํ ์ฝ๋๊ฐ ๋ง๊ณ , โก ์์กด๊ด๊ณ์ ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค์ ์์กดํ์ฌ DIP, OCP๋ฅผ ์๋ฐํ ๊ฐ๋ฅ์ฑ์ด ๋์ผ๋ฉฐ*, โข ํ ์คํธํ๊ธฐ ์ด๋ ต๋จ ์ด์ ๋ฑ์ผ๋ก ์ ์ฐ์ฑ์ด ๋จ์ด์ง๋ค.
public class SingletonService {
public static final SingletonService instance = new SingletonService();
...
}
* ํด๋ผ์ด์ธํธ๊ฐ ๊ตฌ์ฒด ํด๋์ค(SingletonService)์ ์์กดํ๋ฉฐ DIP, OCP๋ฅผ ์๋ฐํ๋ค.
์ฑ๊ธํค ์ปจํ ์ด๋
- ์ฑ๊ธํค ํจํด์ ๋จ์ ์ ๋ณด์ํ์๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ ์ฑ๊ธํค ์ปจํ ์ด๋์ ์ญํ ์ ํ๋ค.
์ด๋ ๊ฒ ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์์ฑ, ๊ด๋ฆฌํ๋ ๊ธฐ๋ฅ์ ์ฑ๊ธํค ๋ ์ง์คํธ๋ฆฌ(Singleton Registry)๋ผ๊ณ ํ๋ค.
- ์คํ๋ง ์ปจํ ์ด๋๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ์ด์ ๋ถํด ์ฑ๊ธํค ํจํด ์ฝ๋๋ฅผ ์์ฑํ์ง ์์๋ ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์ถ์ํ์๋ง ์์กดํ๋ฏ๋ก DIP, OCP๋ฅผ ์ค์ํ๋ฉฐ, ํ ์คํธ๋ก๋ถํฐ ์์ ๋กญ๊ฒ ์ฑ๊ธํค์ ์ฌ์ฉํ ์ ์๋ค.
์ฑ๊ธํค ๋ฐฉ์์ ์ฃผ์์
๋ฌด์ํ(stateless)๋ก ์ค๊ณํด์ผ ํ๋ค!
์ฑ๊ธํค ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ํ๋์ ๊ฐ์ฒด ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๋ค. ์ด๋ ์ฑ๊ธํค ๊ฐ์ฒด๋ ์ํ๋ฅผ ์ ์ง(stateful)ํ๊ฒ ์ค๊ณํ๋ฉด ์ ๋๋ค. ํ๋์ ๊ฐ์ฒด๋ฅผ ๊ณต์ ํ๋ ์ฑ๊ธํค ํจํด์ ํน์ฑ์ ์ํ๊ฐ ๊ณต์ ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
StatefulSerice.java
class StatefulService {
private int price; //์ํ๋ฅผ ์ ์งํ๋ ํ๋ 10000 -> 20000
public int order(String name, int price) {
System.out.println("name = " + name + " price = " + price);
this.price = price; //์ฌ๊ธฐ๊ฐ ๋ฌธ์ !
}
public int getPrice() {
return price;
}
}
StatefulSericeTest.java
class StatefulServiceTest {
@Test
void statefulServiceSingleton() {
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean(StatefulService.class);
StatefulService statefulService2 = ac.getBean(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);
assertThat(statefulService1.getPrice()).isEqualTo(statefulService2.getPrice());
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
StatefulService์ order ๋ฉ์๋๋ ์ด๋ฆ, ๊ฐ๊ฒฉ์ ๋ฐ์ price ๋ณ์์ ์ ์ฅํ๋ค.
StatefulServiceTest์์ ์ฌ์ฉ์ A๋ 10,000์, B๋ 20,000์์ order ๋ฉ์๋์ ๋๊ฒจ์คฌ์ ๋, StatefulService์ price๋ 10,000์ด ์ ์ฅ๋ ํ B๊ฐ ์ฃผ๋ฌธํ ์ ๋ณด๋ฅผ ๋๊ธฐ๋ฉฐ 20,000์ผ๋ก ๋ฐ๋๋ค.
๋ฐ๋ผ์ ์ฌ์ฉ์ A์ ์ฃผ๋ฌธ ๊ธ์ก์ ์กฐํํ๋ฉด price์ ๋ง์ง๋ง์ผ๋ก ์ ์ฅ๋ 20000์ด๋ผ๋ ์๋ชป๋ ๊ฐ์ด ๋ฐํ๋๋ค.
์ค๋ฌด์์ ๊ฐ์ฒด๋ฅผ statefulํ๊ฒ ์ค๊ณํ๋ค๋ฉด, ๋ก๊ทธ์ธ์ ํ์ ๋ ๋ค๋ฅธ ์ฌ๋์ ์ ๋ณด๊ฐ ๋ ธ์ถ๋๋ ๋ฑ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค!!!๐จ
๋ฐ๋ผ์ ๊ฐ์ฒด๋ ๋ฌด์ํ๋ก ์ค๊ณ๋์ด์ผ ํ๋ค.
๋ฌด์ํ๋ก ์ค๊ณํ๋ค๋ ๊ฒ(stateless)์ ์ํ๋ฅผ ๊ณต์ ํ๋ ํ๋ ๋ณ์๊ฐ ์๋ ๊ฒ์ ์๋ฏธํ๋ค. ๋ค์ ์กฐ๊ฑด์ ์งํค๋ฉฐ ์ค๊ณํ์.
1. ํน์ ํด๋ผ์ด์ธํธ๊ฐ ์์กด์ ์ธ ํ๋๊ฐ ์์ผ๋ฉด ์๋จ
2. ํน์ ํด๋ผ์ด์ธํธ๊ฐ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ํ๋๊ฐ ์์ผ๋ฉด ์๋จ
3. ๊ฐ๊ธ์ ์ฝ๊ธฐ๋ง ๊ฐ๋ฅํด์ผ ํจ
4. ํ๋ ๋์ ์๋ฐ์์ ๊ณต์ ๋์ง ์๋ ์ง์ญ๋ณ์, ํ๋ผ๋ฏธํฐ, ThreadLocal ๋ฑ์ ์ฌ์ฉํด์ผํจ
* ThreadLocal : Thread ๋จ์๋ก ๋ก์ปฌ๋ณ์ ์ฌ์ฉ ๊ฐ๋ฅ
์ ์์ ๋ฅผ ๋ฌด์ํ๋ก ์ค๊ณํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
StatefulSerice.java
class StatefulService {
public int order(String name, int price) {
System.out.println("name = " + name + " price = " + price);
return price;
}
}
StatefulSericeTest.java
class StatefulServiceTest {
@Test
void statefulServiceSingleton() {
...
//ThreadA : A ์ฌ์ฉ์ 10000์ ์ฃผ๋ฌธ
int userAPrice = statefulService1.order("userA", 10000);
//ThreadB : B ์ฌ์ฉ์ 20000์ ์ฃผ๋ฌธ
int userBPrice = statefulService2.order("userB", 20000);
//ThreadA : ์ฌ์ฉ์ A ์ฃผ๋ฌธ ๊ธ์ก ์กฐํ
System.out.println("price = " + userAPrice);
}
...
}
์ํ๋ฅผ ๊ณต์ ํ๋ ๋ณ์์ธ price๋ฅผ ์์ ๊ณ order ๋ฉ์๋์ ๋ฐํ๊ฐ์ผ๋ก price๋ฅผ ๋ฆฌํดํ๋ฉฐ ์ฌ์ฉ์ ๊ฐ๊ฐ์ ์ฃผ๋ฌธ ๊ธ์ก์ ์ ํํ๊ฒ ์กฐํํ ์ ์๊ฒ ๋์๋ค.
+ @Configuration๊ณผ ์ฑ๊ธํค
@Configuration๊ณผ ์ฑ๊ธํค
AppConfig๋ฅผ ๋ณด๋ฉด memberService, orderService ๋น์ ๋ง๋ค๋ ๋์ผํ๊ฒ new MemoryMemberRepository๋ฅผ ์ํํจ
-> 2๊ฐ์ ๋ค๋ฅธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๋ฉฐ ์ฑ๊ธํค์ด ๊นจ์ง๋ ๊ฒ์ธ๊ฐ?
-> ํ
์คํธ ์ฝ๋๋ก ๊ฐ์ฒด ๋น๊ต ๊ฒฐ๊ณผ, ๋์ผํ ์ฐธ์กฐ ๊ฐ์ ๊ฐ์ง๋ค๋ ๊ฑธ ์ ์ ์๋ค. ๊ฐ์ ์ธ์คํด์ค๊ฐ ๊ณต์ ๋๊ณ ์๋ ๊ฒ!
-> ๋๋ฒ newํ๋๋ฐ ์ด๋ป๊ฒ ์ด๊ฒ ๊ฐ๋ฅ? ๋ ๋ฒ ํธ์ถ์ด ์๋๋๊ฑฐ ์๋?
-> ใ
ใ
new MemoryMemberRepository๋ ํ ๋ฒ๋ง ์ํ๋จ
-> ์ด๊ฒ ๊ฐ๋ฅํ ์ด์ ๋?
@Configuration๊ณผ ๋ฐ์ดํธ์ฝ๋ ์กฐ์
AppConfig.java์ @Configuration์ด ์ด๋ฅผ ๊ฐ๋ฅ์ผ ํด์ค๋ค.
AppConfig์ ๋น์ ์กฐํํ์ฌ ํด๋์ค ์ ๋ณด๋ฅผ ๋ณด๋ฉด class hello.core.AppConfig๊ฐ ์๋ xxxCGLIB๊ฐ ๋ถ์ ํด๋์ค๊ฐ ์กฐํ๋๋ค
- ์ด๋ ๋ด๊ฐ ๋ง๋ AppConfig์๋ ๋ค๋ฆ
- ์คํ๋ง์ด GBLIB๋ผ๋ ๋ฐ์ดํธ ์กฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ AppConfigํด๋์ค๋ฅผ ์์๋ฐ์ ์์์ ํด๋์ค๋ฅผ ๋ง๋ ๊ฒ! ๊ทธ๋ฆฌ๊ณ AppConfig๊ฐ ์๋ ๋ฐ์ดํธ ์กฐ์๋ AppConfig ํด๋์ค๊ฐ ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๋ค
- ์ด ์์์ ํด๋์ค๊ฐ ์ฑ๊ธํค์ ๋ณด์ฅํด์ค : Bean์ด ๋ถ์ ๋ฉ์๋์ ์คํ๋ง ๋น์ด ์ด๋ฏธ ์กด์ฌํ๋ฉด ์กด์ฌํ๋ ๋น์ ์ฐพ์ ๋ฐํ / ์คํ๋ง ๋น์ด ์๋ค๋ฉด ์์ฑ, ์คํ๋ง ๋น์ผ๋ก ๋ฑ๋ก ํ ๋ฐํ
AppConfig@CGLIB ์์ ํด๋์ค ๋ด๋ถ ๊ตฌ์กฐ
@Bean
public MemberRepository memberRepository() {
if (memoryMemberRepository in ์คํ๋ง ์ปจํ
์ด๋)
return ์คํ๋ง ์ปจํ
์ด๋์์ ์ธ์คํด์ค ์ฐพ์์ ๋ฐํ
else
๊ธฐ์กด ๋ก์ง(new)์ ํธ์ถํด์ MemoryMemberRepository ์์ฑ & ์คํ๋ง ์ปจํ
์ด๋์ ๋ฑ๋ก
return ์ธ์คํด์ค ๋ฐํ
}
@Configuration์ ์ ์ฉํ์ง ์๊ณ @Bean๋ง ์ ์ฉํ๋ค๋ฉด?
์คํ๋ง ๋น์ ์์ฑ๋์ง๋ง ์ฑ๊ธํค์ ๋ณด์ฅ ์ ๋จ
์ด๋, AppConfig ๋ฉ์๋์ new์ฐ์ฐ์ ๊ตฌ์ฒด ํด๋์ค๋ฅผ ํ ๋นํ ๊ฒ๊ณผ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋(MemberRepository memberRepository = new MemoryMemberRepository() - DIP, OCP ์๋ฐ!)
⇒ ์คํ๋ง ์ค์ ์ ๋ณด๋ ํญ์ @Configuration์ ์ฌ์ฉํ ๊ฒ!
'Spring ๐ฑ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring JPA] Entity์ @Setter๋ฅผ ์ง์ํด์ผ ํ๋ ์ด์ (0) | 2023.07.27 |
---|---|
[JPA] ์์์ฑ ์ปจํ ์คํธ (0) | 2023.07.25 |
๋น๋ ํจํด(Builder Pattern) (0) | 2023.07.17 |
[Spring] ์์กด์ฑ ์ฃผ์ (DI)์ด๋? (0) | 2023.07.13 |
[Spring] JUnit5์ assertJ๋ก ํ ์คํธ ์ฝ๋ ์์ฑํ๊ธฐ (0) | 2023.06.19 |