μΌ | μ | ν | μ | λͺ© | κΈ | ν |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- Dependency Injection
- builder
- factory
- Google OAuth
- OAuth 2.0
- spring security
- μΌκΈ κ°μ²΄
- lombok
- μΌκΈ 컬λ μ
- middleware
- java
- synchronized
- Spring
- Volatile
- nestjs
- Today
- Total
HJW's IT Blog
μ€νλ§ μ±κΈν€ 컨ν μ΄λμ λμ μ리 λ³Έλ¬Έ
π μΉ μ΄ν리μΌμ΄μ κ³Ό μ±κΈν€
μ€νλ§μ νμμ΄ κΈ°μ μ© μ¨λΌμΈ μλΉμ€ κΈ°μ μ μ§μνκΈ° μν΄ νμνλ€. κ·Έλ κΈ°μ λλΆλΆμ μ€νλ§ μ΄ν리μΌμ΄μ μ μΉ μ΄ν리μΌμ΄μ μ΄λ€. μΉ μ΄ν리μΌμ΄μ μ νΉμ§μ, λ³΄ν΅ μ¬λ¬ κ³ κ°μ΄ λμ μμ²μ 보λΈλ€λ μ μ΄λ€. κ·Έλ λ€λ©΄ μ΄ν리μΌμ΄μ μ΄ μ»€μ§κ³ , νΈλ ν½μ΄ λ§μμ§ μλ‘, κ°μ²΄ μμ± λΉμ©κ³Ό λ©λͺ¨λ¦¬ μ¬μ©λμ μ¦κ°νκ² λκ³ , λ§μ 리μμ€λ₯Ό μλͺ¨νλ€λ λ»μ΄λ€.

λ€μμ, μ€νλ§μ΄ μλ μμν DI 컨ν μ΄λ ν μ€νΈ μμμ΄λ€.
public class SingletonTest {
@Test
@DisplayName("μ€νλ§ μλ μμ DI 컨ν
μ΄λ")
void pureContainer(){
AppConfig appConfig = new AppConfig();
MemberService memberService1 = appConfig.memberService();
MemberService memberService2 = appConfig.memberService();
System.out.println("1 : " + memberService1);
System.out.println("2 : " + memberService2);
Assertions.assertThat(memberService1).isNotEqualTo(memberService2);
}
}

κ²°κ³Όλ₯Ό 보면, μ°Έμ‘°κ°λ λ€λ₯΄κ³ , isNotEqualTo ν μ€νΈλ ν΅κ³Όλλ κ²μ λ³Ό μ μλ€.
μ΄ ν μ€νΈμ μλ―Έλ, μμν DI ContainerμΈ AppConfigλ μμ²λ§λ€ κ°μ²΄λ₯Ό μλ‘ μμ±νλ€. λ¬Όλ‘ μμ² μκ° μ λ€λ©΄ μκ΄ μμ κ²μ΄λ€. νμ§λ§, λ§μ½ κ³ κ° νΈλν½μ΄ μ΄λΉ 100μ΄λΌλ©΄, μ΄λΉ 100κ°μ κ°μ²΄κ° μμ±λκ³ μλ©Έλλλ°, λ©λͺ¨λ¦¬ λλΉκ° λ§€μ° μ¬νλ€.
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μ±λ€ν€ ν¨ν΄μ μ¬μ©νλ€.
πμ±κΈν€ ν¨ν΄
μ±κΈν€ ν¨ν΄μ΄λ, ν΄λμ€μ μΈμ€ν΄μ€κ° λ± 1κ°λ§ μμ±λλ κ²μ 보μ₯νλ λμμΈ ν¨ν΄μ΄λ€. κ·Έλ κΈ°μ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό 2κ° μ΄μ μμ±νμ§ λͺ»νλλ‘ λ§μμΌ νλ€.
- μμ±μλ₯Ό private μ μ¬μ©νμ¬, μΈλΆμμ μμλ‘ new ν€μλλ‘ κ°μ²΄λ₯Ό μμ±νλκ²μ λ§λλ€.
λ€μμ μ±κΈν€ ν¨ν΄μ μμμ΄λ€.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance(){
return instance;
}
private SingletonService(){
}
public void logic(){
System.out.println("μ±κΈν€ κ°μ²΄ νΈμΆ");
}
}
- static μμμ κ°μ²΄ instance λ₯Ό 미리 νλ μμ±νμ¬ μ¬λ €λλ€
- μ΄ κ°μ²΄ μΈμ€ν΄μ€κ° νμνλ©΄ μ€μ§ getInstance() λ©μλλ₯Ό ν΅ν΄μλ§ νΈμΆμ΄ κ°λ₯νλ€
- λ± 1κ°μ κ°μ²΄ μΈμ€ν΄μ€λ§ μ‘΄μ¬ν΄μΌ νλ―λ‘ μμ±μλ₯Ό private μΌλ‘ μ€μ νμ¬ μΈλΆμμ new ν€μλλ‘μ μ κ·Όμ λ§μμΌ νλ€.
νλ² μ΄ μ±κΈν€μ΄ μ§μ§ μ±κΈν€μΈμ§ νμΈν΄ 보μ. μ΄μ DI ν μ€νΈμμ , λκ°μ μΈμ€ν΄μ€λ₯Ό μμ±νλ©΄ μ°Έμ‘°κ°μ΄ μλ‘ λ¬λλ κ²μ κΈ°μ΅νμ.
@Test
@DisplayName("μ±κΈν€ κ°μ²΄ ν
μ€νΈ")
void singletonServiceTest(){
SingletonService singletonService1 = SingletonService.getInstance();
SingletonService singletonService2 = SingletonService.getInstance();
System.out.println("1 : " + singletonService1);
System.out.println("2 : " + singletonService2);
Assertions.assertThat(singletonService1).isSameAs(singletonService2);
singletonService1.logic();
}
κ²°κ³Ό

μ±κΈν€ ν¨ν΄μ λ¬Έμ μ
μ±κΈν€ ν¨ν΄μ κ°μ²΄λ₯Ό 곡μ νμ¬ ν¨μ¨μ μΌλ‘ μ¬μ©ν μ μμ§λ§, μλ§μ λ¬Έμ μ λ€μ κ°μ§κ³ μλ€.
- μ±κΈν€ ν¨ν΄μ ꡬννλ μ½λ μμ²΄κ° λ§μ΄ λ€μ΄κ°λ€.
- μμ‘΄κ΄κ³μ ν΄λΌμ΄μΈνΈκ° ꡬ체 ν΄λμ€μ μμ‘΄νλ€. → DIP μλ°
- ν΄λΌμ΄μΈνΈκ° ꡬ체 ν΄λμ€μ μμ‘΄ν΄μ OCP μμΉμ μλ°ν κ°λ₯μ±μ΄ λλ€.
- ν μ€νΈ νκΈ° μ΄λ ΅λ€
- λ΄λΆ μμ±μ λ³κ²½νκ±°λ μ΄κΈ°ν νκΈ° μ΄λ ΅λ€
- private μμ±μλ‘ μμ μμ±μλ‘ μμ ν΄λμ€λ₯Ό λ§λ€κΈ° μ΄λ ΅λ€.
- μ μ°μ±μ΄ λ¨μ΄μ§λ€
π μ±κΈν€ 컨ν μ΄λ
Spring Container λ μ±κΈν€ ν¨ν΄μ λ¬Έμ μ μ ν΄κ²°νλ©΄μ, κ°μ²΄ μΈμ€ν΄μ€λ₯Ό μ±κΈν€μΌλ‘ κ΄λ¦¬νλ€. Spring Bean μ κΈ°λ³Έμ μΌλ‘ μ±κΈν€μΌλ‘ κ΄λ¦¬λλ€.
μ±κΈν€ 컨ν μ΄λ
- Spring Container λ μ±κΈν€ ν¨ν΄μ μ μ©νμ§ μμλ κ°μ²΄ μΈμ€ν΄μ€λ₯Ό μ±κΈν€μΌλ‘ κ΄λ¦¬νλ€.
- Spring Container λ μ±κΈν€ 컨ν μ΄λ μν μ νλ€. → μ±κΈν€ κ°μ²΄λ₯Ό μμ±νκ³ κ΄λ¦¬νλ κΈ°λ₯μ Singleton RegistryλΌ νλ€.
- Spring Container μ μ΄λ° κΈ°λ₯ λμ μ±κΈν€μ λͺ¨λ λ¨μ μ ν΄κ²°νλ©΄μ, κ°μ²΄λ₯Ό μ±κΈν€μΌλ‘ μ μ§ν μ μλ€.
@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("1 : " + memberService1);
System.out.println("2 : " + memberService2);
Assertions.assertThat(memberService1).isSameAs(memberService2);
}

μ΄μ ν μ€νΈλ μ§μ μμ±ν μ±κΈν€ ν΄λμ€μ ν μ€νΈμλ€. μ΄λ² ν μ€νΈλ Spring Container μ λ±λ‘λμ΄ μ»¨ν μ΄λκ° bean λ€μ μ±κΈν€μΌλ‘ κ΄λ¦¬νλμ§ κ²μ¦νκΈ° μν ν μ€νΈμ΄λ€. μ°Έμ‘°κ°λ κ°κ³ ν μ€νΈλ ν΅κ³Όνλ€.
μ±κΈν€ 컨ν μ΄λ μ μ© ν λͺ¨μ΅

πμ±κΈν€ λ°©μμ μ£Όμμ
μ±κΈν€μ μ΄μ μ μΈκΈνλ―, μ¬λ¬ μ¬μ©μκ° κ³΅μ νλ κ°μ²΄ μΈμ€ν΄μ€μ΄λ€. κ·Έλ κΈ° λλ¬Έμ, μ±κΈν€ κ°μ²΄λ μνλ₯Ό μ μ§ν΄μ μλλ€. (Stateless)
- νΉμ ν΄λΌμ΄μΈνΈμ μμ‘΄μ μΈ νλκ° μμ΄μλ μλλ€
- νΉμ ν΄λΌμ΄μΈνΈκ° κ°μ λ³κ²½ν μ μλ νλκ° μμ΄μ μλλ€.
- κ°κΈμ ReadOnly
- νλ λμ μ μλ°μμ 곡μ λμ§ μλ μ§μλ³μ, νλΌλ―Έν°, ThreadLocal λ±μ μ¬μ©ν΄μΌ νλ€
Stateful μμ
package hello.core.singleton;
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);
statefulService1.order("userA", 10000);
statefulService2.order("userB", 20000);
int price = statefulService1.getPrice();
System.out.println(price);
Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}
static class TestConfig {
@Bean
public StatefulService statefulService() {
return new StatefulService();
}
}
}
price λ₯Ό μ‘°ννλ©΄, μ°λ¦¬μ μλλλ‘λΌλ©΄ 10000μμ΄μ΄μΌ νλ€. νμ§λ§, μ€μ μ€ν κ²°κ³Όλ 20000μ΄ λμ¨λ€.. → κ°μ μΈμ€ν΄μ€λ₯Ό 곡μ νκΈ° λλ¬Έ.

κ·Έλμ μ°λ¦¬λ λ€μκ³Ό κ°μ΄ μ€κ³λ₯Ό ν΄μΌ νλ€
public class StatefulService {
// private int price;
public int order(String name, int price){
System.out.println("name = " + name + " price = " + price );
return price;
}
// public int getPrice(){
// return price;
// }
}
@Test
void statefulServiceSingleton(){
ApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
StatefulService statefulService1 = ac.getBean("statefulService", StatefulService.class);
StatefulService statefulService2 = ac.getBean("statefulService", StatefulService.class);
int userA = statefulService1.order("userA", 10000);
int userB = statefulService2.order("userB", 20000);
System.out.println(userA);
// Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
}

@Configuration κ³Ό μ±κΈν€
μ΄μ μ μμ±ν AppConfig μ½λλ₯Ό νλ² μ΄ν΄λ³΄μ
@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 μμ νΈμΆνλ memberRepository λ new ν€μλλ‘ μμ±μ΄ λκ³ , orderService μμ νΈμΆνλ memberRepository λν new ν€μλλ‘ μμ±μ΄ λλ€.
- κ·Έλ λ€λ©΄ μ±κΈν€μ΄ κΉ¨μ§λ κ²μΌκΉ?
κ²°λ‘ λΆν° λ§νμλ©΄, μ±κΈν€μ κΉ¨μ§μ§ μλλ€. ν μ€νΈλ‘ κ²μ¦ν΄ 보μ.
κ° OrderServiceImpl κ³Ό MemberServiceImpl μ memberRepository λ₯Ό λ°ννλ μμ λ©μλλ₯Ό λ§λ ν, ν μ€νΈλ₯Ό μμ±νμ.
@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("1 : " + memberService.getMemberRepository());
System.out.println("2 : " + orderService.getMemberRepository());
System.out.println("3 : " + memberRepository);
}

λͺ¨λ κ°μ μ°Έμ‘°κ°μ κ°λ₯΄ν€κ³ μλ€.
νλ² AppConfig μ λ‘κ·Έλ₯Ό μ°μ΄ νμΈν΄ 보μ.
@Bean
public MemberService memberService(){
System.out.println("Calling memberService");
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService(){
System.out.println("Calling orderService");
return new OrderServiceImpl(memberRepository(), discountPolicy());
}
@Bean
public MemberRepository memberRepository(){
System.out.println("Calling memberRepository");
return new MemoryMemberRepository();
}
λΆλͺ memberService μμλ, orderService μμλ memberRepository λ©μλλ₯Ό ν΅ν new ν€μλλ₯Ό μ¬μ©νκΈ°μ, “Calling memberRepository” κ° 3λ² μΆλ ₯λμ΄μΌ ν κ² κ°λ€. νμ§λ§ κ²°κ³Όλ λ€μκ³Ό κ°λ€

memberRepository λ λ¨ νλ²λ§ νΈμΆλλ€.
@Configuration κ³Ό λ°μ΄νΈ μ½λ μ‘°μ
Spring μ Bean μ κΈ°λ³Έμ μΌλ‘ μ±κΈν€ Scope λ₯Ό κ°μ§λ€κ³ μ΄λ―Έ μ€λͺ νλ€. Spring μ μ΄λ₯Ό μ΄λ»κ² 보μ₯ν κΉ?
CGLIB νλ‘μλ₯Ό ν΅ν΄ μ±κΈν€μ 보μ₯νλ€. @Configurationμ΄ λΆμ ν΄λμ€μ Bean λ€μ μ€νλ§μ λ°νμμ, CGLIB Proxy λ‘ κ°μΈμ λ©μλ νΈμΆμ κ°λ‘μ±λ€. μ¦, @Configuration ν΄λμ€ λ΄μμ λ€λ₯Έ @Bean λ©μλλ₯Ό νΈμΆ νλλΌλ, μ€μ λ‘ ν΄λΉ λ©μλκ° μ€ν λλ κ²μ΄ μλ, νλ‘μκ° κ°λ‘μ±λ νμμΌλ‘ μλνλ κ²μ΄λ€.
CGLIBλ₯Ό ν΅ν νλ‘μ μμ±
- Spring μ μλ³Έ @Configuration ν΄λμ€λ₯Ό μμλ°λ νλ‘μ μλΈν΄λμ€λ₯Ό μμ±νλ€. μ΄ νλ‘μ ν΄λμ€λ μλ³Έ ν΄λμ€μ λͺ¨λ λ©μλλ₯Ό μ€λ²λΌμ΄λ νλ€
- CGLIBλ λ°μ΄νΈ μ½λ μμ€μμ ν΄λμ€μ λ©μλλ₯Ό μ‘°μνλ μλ‘μ΄ κΈ°λ₯μ μΆκ°νμ¬, λ©μλ νΈμΆμ κ°λ‘μ±κ±°λ μνλ λ‘μ§μ μ½μ νλ€.
- μ€λ²λΌμ΄λλ @Bean λ©μλ λ€μ μ€μ λ‘λ Spring 컨ν μ΄λμμ Bean μ μ‘°ν / μμ±νλ λ‘μ§μ ν¬ν¨νλ€. μ΄λ‘μ¨, ν΄λμ€μ λ©μλ νΈμΆμ, λ³Έλ¬Έμ΄ μλ 컨ν μ΄λλ₯Ό ν΅ν΄ κ΄λ¦¬λ Bean μ΄ λ°νλλ κ²μ΄λ€.
λμ κ³Όμ
- 컨ν μ΄λ μ΄κΈ°νμ, memberService() κ° νΈμΆλκ³ , μ΄ μμμ memberRepository() κ° νΈμΆλλ€. μ΄λ, νλ‘μ λ©μλλ 컨ν μ΄λμ memberRepository Bean μ΄ μ‘΄μ¬νλμ§ νμΈνλλ°, μμΌλ―λ‘, super.memberRepository() λ₯Ό νΈμΆνμ¬ μλ³Έ λ©μλμ λ³Έλ¬Έμ μ€ννκ³ Bean μ μμ± λ° μ»¨ν μ΄λμ λ±λ‘νκ² λλ€.
- memberRepository μ λλ²μ§Έ, μΈλ²μ§Έ νΈμΆμ, νλ‘μ λ©μλλ 컨ν μ΄λμ ν΄λΉ bean μ΄ μ΄λ―Έ μ‘΄μ¬ν¨μ νμΈνκ³ , μλ³Έ λ©μλμ λ³Έλ¬Έμ μ€ννλ λμ , 컨ν μ΄λμ λ±λ‘λ κΈ°μ‘΄μ μ±κΈν€ bean μ λ°ννκ² λλ€.
@Test
void configurationDeep(){
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
- μ¬μ€ AnnotationConfigApplicationContext μ νλΌλ―Έν°λ‘ λκΈ΄ κ°μ Spring Bean μΌλ‘ λ±λ‘μ΄ λλ€.
μΆλ ₯κ²°κ³Ό
bean = class hello.core.AppConfig$$SpringCGLIB$$0
μ¦, μ°λ¦¬κ° μ¬μ©νλ ν΄λμ€λ, μ°λ¦¬κ° μμ±ν ν΄λμ€κ° μλ, CGLIB λΌλ λ°μ΄νΈμ½λ μ‘°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν΄μ AppConfig λ₯Ό μμλ°μ μμμ λ€λ₯Έ ν΄λμ€λ₯Ό μ€νλ§ λΉμΌλ‘ λ±λ‘ν κ²μ΄λ€.

μ΄λ₯Ό ν΅ν΄ μ±κΈν€μ΄ 보μ₯λλ€.
νλ² @Configuration μ΄λ Έν μ΄μ μ μ§μ°κ³ μ€νν΄ λ³΄μ

μ΄μ κ³Ό λ¬λ¦¬ memberRepository κ° 3λ² νΈμΆλλκ²μ λ³Ό μ μλ€.
μ 리
- μ±κΈν€ ν¨ν΄μ κ°μ²΄ μ¬μ¬μ© μΈ‘λ©΄μμ ν¨μ¨μ μ΄μ§λ§, μ§μ ꡬν μ μ μ°μ±, ν μ€νΈμ±, μ μ§λ³΄μμ± μΈ‘λ©΄μμ μ΄λ €μμ κ²ͺλλ€.
- μ€νλ§ μ»¨ν μ΄λλ λ³λμ ꡬν μμ΄ Beanμ μ±κΈν€μΌλ‘ κ΄λ¦¬ν΄ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νλ€.
- μ±κΈν€μΌλ‘ Beanμ κ΄λ¦¬ν λλ μνλ₯Ό κ°μ§μ§ μλλ‘ μ£Όμν΄μΌ νλ€.
- @Configurationκ³Ό CGLIB νλ‘μλ₯Ό ν΅ν΄ μ€νλ§μ λμΌν Beanμ μμ² μ νμ κ°μ μΈμ€ν΄μ€λ₯Ό λ°ννλ λ©μ»€λμ¦μ κ°μΆκ³ μλ€.
- λ€μ€ μ¬μ©μ μμ²μ΄ λ°μνλ μΉ μ ν리μΌμ΄μ νκ²½μμλ νΉν μ£Όμν΄μΌ νλ©°, Stateless μ€κ³λ₯Ό ν΅ν΄ μμ νκ³ μΌκ΄μ± μλ μ ν리μΌμ΄μ μ ꡬμΆν μ μλ€.
'SPRING' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
μ€νλ§ λΉ μ΄κΈ°νΒ·μλ©Έ λ‘μ§ : μΈν°νμ΄μ€, Bean, @PostConstruct (0) | 2024.12.12 |
---|---|
μ»΄ν¬λνΈ μ€μΊκ³Ό μμ‘΄μ± μλ μ£Όμ (0) | 2024.12.04 |
μ€νλ§ μ»¨ν μ΄λμ μ€νλ§ λΉ (1) | 2024.11.29 |
κ°μ²΄ μ§ν₯ μ€κ³μ μ€νλ§ (2) | 2024.11.27 |
AOP κΈ°λ³Έ κ°λ μ 리 (1) | 2024.11.27 |