STUDYπŸ„

[Spring κΈ°λ³Έ] 9. 빈 μŠ€μ½”ν”„

쏴리쏭 2025. 6. 2. 22:16

μ•ˆλ…•ν•˜μ„Έμš”!

λ“œλ””μ–΄ λ§ˆμ§€λ§‰ μ„Ήμ…˜μž…λ‹ˆλ‹€!

그럼 λ°”λ‘œ μ‹œμž‘ν•΄λ³Όκ²Œμš” κ³ κ³ !!


1. 빈 μŠ€μ½”ν”„λž€..?

μ§€κΈˆκΉŒμ§€ μŠ€ν”„λ§ 빈이 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ˜ μ‹œμž‘κ³Ό ν•¨κ»˜ μƒμ„±λ˜μ–΄μ„œ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ’…λ£Œλ  λ•ŒκΉŒμ§€ μœ μ§€λœλ‹€κ³  κ³΅λΆ€ν–ˆμŠ΅λ‹ˆλ‹€.

이것은 μŠ€ν”„λ§ 빈이 기본적으둜 싱글톀 μŠ€μ½”ν”„λ‘œ μƒμ„±λ˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

μŠ€μ½”ν”„λŠ” λ²ˆμ—­ κ·ΈλŒ€λ‘œ 빈이 μ‘΄μž¬ν•  수 μžˆλŠ” λ²”μœ„λ₯Ό λœ»ν•©λ‹ˆλ‹€.

 

μŠ€ν”„λ§μ€ λ‹€μŒκ³Ό 같은 λ‹€μ–‘ν•œ μŠ€μ½”ν”„λ₯Ό μ§€μ›ν•©λ‹ˆλ‹€.

  • 싱글톀: κΈ°λ³Έ μŠ€μ½”ν”„μž…λ‹ˆλ‹€. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ˜ μ‹œμž‘κ³Ό μ’…λ£ŒκΉŒμ§€ μœ μ§€λ˜λŠ” κ°€μž₯ 넓은 λ²”μœ„μ˜ μŠ€μ½”ν”„μž…λ‹ˆλ‹€.
  • ν”„λ‘œν† νƒ€μž…: μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” ν”„λ‘œν† νƒ€μž… 빈의 생성과 μ˜μ‘΄κ΄€κ³„ μ£Όμž…κΉŒμ§€λ§Œ κ΄€μ—¬ν•˜κ³  λ”λŠ” κ΄€λ¦¬ν•˜μ§€ μ•ŠλŠ” 맀우 짧은 λ²”μœ„μ˜ μŠ€μ½”ν”„μž…λ‹ˆλ‹€.
  • μ›Ή κ΄€λ ¨ μŠ€μ½”ν”„
    • request: μ›Ή μš”μ²­μ΄ λ“€μ–΄μ˜€κ³  λ‚˜κ°ˆ λ•ŒκΉŒμ§€ μœ μ§€λ˜λŠ” μŠ€μ½”ν”„μž…λ‹ˆλ‹€.
    • session: μ›Ή μ„Έμ…˜μ΄ μƒμ„±λ˜κ³  μ’…λ£Œλ  λ•ŒκΉŒμ§€ μœ μ§€λ˜λŠ” μŠ€μ½”ν”„μž…λ‹ˆλ‹€.
    • application: μ›Ήμ˜ μ„œλΈ”λ¦Ώ μ»¨ν…μŠ€νŠΈμ™€ 같은 λ²”μœ„λ‘œ μœ μ§€λ˜λŠ” μŠ€μ½”ν”„μž…λ‹ˆλ‹€.

 

빈 μŠ€μ½”ν”„λŠ” λ‹€μŒκ³Ό 같이 μ§€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • μ»΄ν¬λ„ŒνŠΈ μŠ€μΊ” μžλ™ 등둝
@Scope("prototype")
@Component
public class HelloBean { }
  • μˆ˜λ™ 등둝
@Scope("prototype")
@Bean
PrototypeBean HelloBean() {
	return new HelloBean();
}

 

μ§€κΈˆκΉŒμ§€ 싱글톀 μŠ€μ½”ν”„λ₯Ό 계속 μ‚¬μš©ν•΄ λ³΄μ•˜μœΌλ‹ˆ, μ΄λ²ˆμ—” ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„λΆ€ν„° ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 


2. ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„

싱글톀 μŠ€μ½”ν”„μ˜ λΉˆμ„ μ‘°νšŒν•˜λ©΄ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” 항상 같은 μΈμŠ€ν„΄μŠ€μ˜ μŠ€ν”„λ§ λΉˆμ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

λ°˜λ©΄μ— ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„λ₯Ό μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μ‘°νšŒν•˜λ©΄ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” 항상 μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

2-1. 싱글톀 빈 μš”μ²­ vs ν”„λ‘œν† νƒ€μž… 빈 μš”μ²­

<⭐싱글톀 빈 μš”μ²­ 과정⭐>

싱글톀 빈 μš”μ²­

1. 싱글톀 μŠ€μ½”ν”„μ˜ λΉˆμ„ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μš”μ²­ν•©λ‹ˆλ‹€.

2. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” 본인이 κ΄€λ¦¬ν•˜λŠ” μŠ€ν”„λ§ λΉˆμ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

3. 이후에 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— 같은 μš”μ²­μ΄ 와도 μŠ€ν”„λ§ λΉˆμ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.

 

<β­ν”„λ‘œν† νƒ€μž… 빈 μš”μ²­ 과정⭐>

ν”„λ‘œν† νƒ€μž… 빈 μš”μ²­1

1. ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„μ˜ λΉˆμ„ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μš”μ²­ν•©λ‹ˆλ‹€.

2. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” 이 μ‹œμ μ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒμ„±ν•˜κ³ , ν•„μš”ν•œ μ˜μ‘΄κ΄€κ³„λ₯Ό μ£Όμž…ν•©λ‹ˆλ‹€.

ν”„λ‘œν† νƒ€μž… 빈 μš”μ²­2

3. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” μƒμ„±ν•œ ν”„λ‘œν† νƒ€μž… λΉˆμ„ ν΄λΌμ΄μ–ΈνŠΈμ— λ°˜ν™˜ν•©λ‹ˆλ‹€.

4. 이후에 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— 같은 μš”μ²­μ΄ 였면 항상 μƒˆλ‘œμš΄ ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

<μ •λ¦¬βœοΈ>

μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒμ„±ν•˜κ³  μ˜μ‘΄κ΄€κ³„ μ£Όμž…κ³Ό μ΄ˆκΈ°ν™”κΉŒμ§€λ§Œ μ²˜λ¦¬ν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.
ν΄λΌμ΄μ–ΈνŠΈμ— λΉˆμ„ λ°˜ν™˜ν•˜κ³ , 이후 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” μƒμ„±λœ ν”„λ‘œν† νƒ€μž… λΉˆμ„ κ΄€λ¦¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
ν”„λ‘œν† νƒ€μž… λΉˆμ„ 관리할 μ±…μž„μ€ ν”„λ‘œν† νƒ€μž… λΉˆμ„ 받은 ν΄λΌμ΄μ–ΈνŠΈμ— 있고, κ·Έλž˜μ„œ @PreDestroy 같은 μ’…λ£Œ λ©”μ„œλ“œκ°€ ν˜ΈμΆœλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

 

 

2-2. 싱글톀 μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈ vs ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈ

μš°μ„  ⭐싱글톀 μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈβ­λΆ€ν„° ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

test의 hello.core에 scopeλΌλŠ” νŒ¨ν‚€μ§€λ₯Ό λ§Œλ“€κ³ , 이 νŒ¨ν‚€μ§€ μ•ˆμ— SingletonTestλΌλŠ” 클래슀λ₯Ό λ§Œλ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

public class SingletonTest {

    @Test
    public void singletonBeanFind() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SingletonBean.class);

        SingletonBean sb1 = ac.getBean(SingletonBean.class);
        SingletonBean sb2 = ac.getBean(SingletonBean.class);

        System.out.println("singletonBean1 = " + sb1);
        System.out.println("singletonBean2 = " + sb2);
        assertThat(sb1).isSameAs(sb2);
        
        ac.close(); //μ’…λ£Œ
    }

    @Scope("singleton")
    static class SingletonBean {
        @PostConstruct
        public void init() {
            System.out.println("SingletonBean.init");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("SingletonBean.destroy");
        }
    }
}

μš°μ„  λ‚΄λΆ€ 클래슀λ₯Ό static class둜 SingletonBean을 λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

μ „ μ„Ήμ…˜μ—μ„œ ν–ˆλ˜ @PostConstruct와 @PreDestroy도 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. 빈 생λͺ…μ£ΌκΈ° μ½œλ°±μ„ μ§€μ›ν•˜κΈ° μœ„ν•΄μ„œμ£ !

κ°€μž₯ νŽΈλ¦¬ν•˜κ²Œ μ΄ˆκΈ°ν™”μ™€ μ’…λ£Œλ₯Ό μ‹€ν–‰ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

 

그러고 메인 ν…ŒμŠ€νŠΈ 클래슀둜 κ°€λ³΄κ² μŠ΅λ‹ˆλ‹€.

μš°μ„ , 늘 ν–ˆλ˜ κ²ƒμ²˜λŸΌ AnnotationConfigApplicationContextλ₯Ό 톡해 SingletonBean 클래슀λ₯Ό μ„€μ •μœΌλ‘œ λ“±λ‘ν•˜μ—¬ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλ₯Ό μƒμ„±ν–ˆμŠ΅λ‹ˆλ‹€.

그리고, getBean() λ©”μ„œλ“œλ‘œ SingletonBean을 2번 μš”μ²­ν–ˆμŠ΅λ‹ˆλ‹€. 이름은 κ΅¬λΆ„λ˜κ²Œ sb1κ³Ό sb2둜 λ‚˜λˆ΄μŠ΅λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ, assertionsλ₯Ό 톡해 두 객체가 같은 μΈμŠ€ν„΄μŠ€μΈμ§€ 확인 μž‘μ—…μ„ ν–ˆμŠ΅λ‹ˆλ‹€.

 

κ²°κ³Όλ₯Ό ν•œ 번 ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

싱글톀 μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈ

두 번의 ν˜ΈμΆœμ—λ„ λ™μΌν•œ 객체가 λ°˜ν™˜λœλ‹€λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

즉, 빈 μ΄ˆκΈ°ν™” λ©”μ„œλ“œλ₯Ό μ‹€ν–‰ν•˜κ³ , 같은 μΈμŠ€ν„΄μŠ€μ˜ λΉˆμ„ μ‘°νšŒν•˜κ³ , μ’…λ£Œ λ©”μ„œλ“œκΉŒμ§€ 정상 호좜된 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

이것이 싱글톀 μŠ€μ½”ν”„ 빈의 νŠΉμ§•μž…λ‹ˆλ‹€!!

 

μ΄λ²ˆμ—λŠ” β­ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈβ­λ₯Ό ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ•žμ„œ λ§Œλ“€μ—ˆλ˜ scopeλΌλŠ” νŒ¨ν‚€μ§€ μ•ˆμ— PrototypeTestλΌλŠ” 클래슀λ₯Ό λ§Œλ“€μ–΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

public class PrototypeTest {

    @Test
    public void prototypeBeanFind() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);

        System.out.println("find pb1");
        PrototypeBean pb1 = ac.getBean(PrototypeBean.class);
        System.out.println("find pb2");
        PrototypeBean pb2 = ac.getBean(PrototypeBean.class);

        System.out.println("prototypeBean1 = " + pb1);
        System.out.println("prototypeBean2 = " + pb2);
        assertThat(pb1).isNotSameAs(pb2);

        ac.close(); //μ’…λ£Œ
    }

    @Scope("prototype")
    static class PrototypeBean {
        @PostConstruct
        public void init() {
            System.out.println("PrototypeBean.init");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("PrototypeBean.destroy");
        }
    }
}

μš°μ„  λ‚΄λΆ€ 클래슀λ₯Ό static class둜 PrototypeBean을 λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

그리고, μ΄ˆκΈ°ν™”μ™€ μ’…λ£Œ λ©”μ„œλ“œλ₯Ό νŽΈν•˜κ²Œ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄ μœ„μ—μ²˜λŸΌ @PostConstruct와 @PreDestroyλ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

@Scope("prototype")은 빈이 μš”μ²­ν•  λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.

그리고, μ΄ˆκΈ°ν™”μ™€ μ’…λ£Œκ°€ 잘 되면 init λ©”μ„œλ“œμ™€ destroy λ©”μ„œλ“œλŠ” 잘 싀행이 λ˜μ–΄μ„œ prototypeBean.initκ³Ό PrototypeBean.destroyκ°€ 좜λ ₯이 λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

메인 ν…ŒμŠ€νŠΈ 클래슀둜 κ°€λ³΄κ² μŠ΅λ‹ˆλ‹€.

μš°μ„ , 늘 ν–ˆλ˜ κ²ƒμ²˜λŸΌ AnnotationConfigApplicationContextλ₯Ό 톡해 PrototypeBean 클래슀λ₯Ό μ„€μ •μœΌλ‘œ λ“±λ‘ν•˜μ—¬ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλ₯Ό μƒμ„±ν–ˆμŠ΅λ‹ˆλ‹€.

그리고, pb1μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ 첫 번째 prototypeBean 객체λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. 이 μ‹œμ μ— 빈이 μƒˆλ‘œ μƒμ„±λ©λ‹ˆλ‹€.

κ·Έ λ‹€μŒ, pb2λΌλŠ” μ΄λ¦„μœΌλ‘œ 또 λ‹€λ₯Έ prototypeBean 객체λ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. prototype μŠ€μ½”ν”„μ΄λ―€λ‘œ μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ©λ‹ˆλ‹€.

ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ λΉˆμ€ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ λΉˆμ„ μ‘°νšŒν•  λ•Œλ§ˆλ‹€ μƒμ„±λ˜κ³ , μ΄ˆκΈ°ν™” λ©”μ„œλ“œλ„ κ·Έ λ•Œ 같이 μ‹€ν–‰λ˜κΈ° λ•Œλ¬Έμ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ 2번 μ‘°νšŒν•˜λ©΄ μ΄ˆκΈ°ν™”λ„ 2번 μ‹€ν–‰λ©λ‹ˆλ‹€.

그러고 λ‚˜μ„œ 두 객체가 μ„œλ‘œ λ‹€λ₯Έ 객체인지 assertThat(pb1).isNotSameAs(pb2);λ₯Ό 톡해 κ²€μ¦ν•©λ‹ˆλ‹€.

 

κ²°κ³Όλ₯Ό ν•œ 번 ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈ

싱글톀 μŠ€μ½”ν”„ 빈 ν…ŒμŠ€νŠΈ λ•Œλž‘μ€ λ‹€λ₯Έ κ²°κ³Όκ°€ λ‚˜μ™”μŠ΅λ‹ˆλ‹€.

μš°μ„  보면, ν™•μ‹€νžˆ λ‹€λ₯Έ κ°μ²΄λΌλŠ” 것이 λ§ˆμ§€λ§‰ 두 쀄에 λ³΄μž…λ‹ˆλ‹€.

 

그러고 보면 μ΄ˆκΈ°ν™”λŠ” λ˜μ—ˆλŠ”λ° μ’…λ£Œκ°€ μ•ˆ λ˜μ—ˆλ‹€λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

destroy λ©”μ„œλ“œκ°€ μ™œ 싀행이 μ•ˆ λ˜μ—ˆμ„κΉŒμš”??πŸ€”

⭐prototype μŠ€μ½”ν”„ λΉˆμ€ μ»¨ν…Œμ΄λ„ˆκ°€ destroy()λ₯Ό μžλ™μœΌλ‘œ ν˜ΈμΆœν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.⭐

μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ 생λͺ…μ£ΌκΈ°λ₯Ό κ΄€λ¦¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄μ£ .

 

μ’…λ£Œκ°€ ν•„μš”ν•˜λ‹€λ©΄ destroy()λ₯Ό μˆ˜λ™μœΌλ‘œ ν˜ΈμΆœν•˜κ±°λ‚˜, λ³„λ„λ‘œ κ΄€λ¦¬ν•˜λŠ” λ‘œμ§μ„ λ§Œλ“€μ–΄μ•Ό ν•©λ‹ˆλ‹€.

 

2-3. 싱글톀 μŠ€μ½”ν”„ 빈과 ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ 빈의 차이점 정리

  • 싱글톀 μŠ€μ½”ν”„ 빈
    • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆ 생성 μ‹œμ μ— μ΄ˆκΈ°ν™” λ©”μ„œλ“œ μ‹€ν–‰λ©λ‹ˆλ‹€.
    • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ κ΄€λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ’…λ£Œλ  λ•Œ 빈의 μ’…λ£Œ λ©”μ„œλ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€.
  • ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ 빈
    • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ λΉˆμ„ μ‘°νšŒν•  λ•Œ μƒμ„±λ˜κ³ , κ·Έ λ•Œ μ΄ˆκΈ°ν™” λ©”μ„œλ“œλ„ μ‹€ν–‰λ©λ‹ˆλ‹€.
    • μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ 생성과 μ˜μ‘΄κ΄€κ³„ μ£Όμž…κ³Ό μ΄ˆκΈ°ν™”κΉŒμ§€λ§Œ κ΄€μ—¬ν•˜κ³  λ”λŠ” κ΄€λ¦¬ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ’…λ£Œλ  λ•Œ @PreDestroy 같은 μ’…λ£Œ λ©”μ„œλ“œλŠ” μ „ν˜€ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
    • κ·Έλž˜μ„œ ν”„λ‘œν† νƒ€μž… λΉˆμ€ ν”„λ‘œν† νƒ€μž… λΉˆμ„ μ‘°νšŒν•œ ν΄λΌμ΄μ–ΈνŠΈκ°€ 관리해야 ν•©λ‹ˆλ‹€.
      μ’…λ£Œ λ©”μ„œλ“œμ— λŒ€ν•œ ν˜ΈμΆœλ„ ν΄λΌμ΄μ–ΈνŠΈκ°€ 직접 ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 


3. ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ - 싱글톀 빈과 ν•¨κ»˜ μ‚¬μš© μ‹œ 문제점

μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„μ˜ λΉˆμ„ μš”μ²­ν•˜λ©΄ 항상 μƒˆλ‘œμš΄ 객체 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄μ„œ λ°˜ν™˜ν•©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ, 싱글톀 빈과 ν•¨κ»˜ μ‚¬μš©ν•  λ•ŒλŠ” μ˜λ„ν•œ λŒ€λ‘œ 잘 λ™μž‘ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

κ·Έλ¦Όκ³Ό μ½”λ“œλ‘œ 봐보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

λ¨Όμ €, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ 직접 μš”μ²­ν•˜λŠ” 예제λ₯Ό 봐보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.

 

<β­ν”„λ‘œν† νƒ€μž… 빈 직접 μš”μ²­β­>

ν”„λ‘œν† νƒ€μž… 빈 직접 μš”μ²­1

1. ν΄λΌμ΄μ–ΈνŠΈAλŠ” μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ μš”μ²­ν•©λ‹ˆλ‹€.

2. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒˆλ‘œ μƒμ„±ν•΄μ„œ λ°˜ν™˜(x01) ν•©λ‹ˆλ‹€. ν•΄λ‹Ή 빈의 count ν•„λ“œ 값은 0 μž…λ‹ˆλ‹€.

3. ν΄λΌμ΄μ–ΈνŠΈλŠ” μ‘°νšŒν•œ ν”„λ‘œν† νƒ€μž… λΉˆμ— addCount()λ₯Ό ν˜ΈμΆœν•˜λ©΄μ„œ count ν•„λ“œλ₯Ό +1 ν•©λ‹ˆλ‹€.

βœ”οΈκ²°κ³Όμ μœΌλ‘œ ν”„λ‘œν† νƒ€μž… 빈(x01)의 countλŠ” 1이 λ©λ‹ˆλ‹€.

ν”„λ‘œν† νƒ€μž… 빈 직접 μš”μ²­2

4. ν΄λΌμ΄μ–ΈνŠΈBλŠ” μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ μš”μ²­ν•©λ‹ˆλ‹€.

5. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒˆλ‘œ μƒμ„±ν•΄μ„œ λ°˜ν™˜(x02) ν•©λ‹ˆλ‹€. ν•΄λ‹Ή 빈의 count ν•„λ“œ 값은 0 μž…λ‹ˆλ‹€.

6. ν΄λΌμ΄μ–ΈνŠΈλŠ” μ‘°νšŒν•œ ν”„λ‘œν† νƒ€μž… λΉˆμ— addCount()λ₯Ό ν˜ΈμΆœν•˜λ©΄μ„œ count ν•„λ“œλ₯Ό +1 ν•©λ‹ˆλ‹€.

βœ”οΈκ²°κ³Όμ μœΌλ‘œ ν”„λ‘œν† νƒ€μž… 빈(x02)의 countλŠ” 1이 λ©λ‹ˆλ‹€.

 

μ½”λ“œλ‘œ ν•œ 번 λ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ•„κΉŒ λ§Œλ“€μ—ˆλ˜ test.hello.core.scope에 SingletonWithPrototypeTest1μ΄λΌλŠ” 클래슀λ₯Ό λ§Œλ“€μ–΄μ€λ‹ˆλ‹€.

public class SingletonWithPrototypeTest1 {

    @Test
    void prototypeFind() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PrototypeBean.class);

        PrototypeBean pb1 = ac.getBean(PrototypeBean.class);
        pb1.addCount();
        assertThat(pb1.getCount()).isEqualTo(1);

        PrototypeBean pb2 = ac.getBean(PrototypeBean.class);
        pb2.addCount();
        assertThat(pb2.getCount()).isEqualTo(1);
    }

    @Scope("prototype")
    static class PrototypeBean {
        private int count = 0;

        public void addCount() {
            count++;
        }

        public int getCount() {
            return count;
        }

        @PostConstruct
        public void init() {
            System.out.println("PrototypeBean.init" + this);
        }

        @PreDestroy
        public void destroy() {
            System.out.println("PrototypeBean.destroy");
        }
    }
}

 

μš°μ„  λ‚΄λΆ€ ν΄λž˜μŠ€λΆ€ν„° λ³΄κ² μŠ΅λ‹ˆλ‹€.

prototype μŠ€μ½”ν”„μ΄λ―€λ‘œ, getBean()을 ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ 객체가 μƒμ„±λ©λ‹ˆλ‹€.

 

μœ„μ˜ κ·Έλ¦Όμ—μ„œ 봀던 addCount()와 getCount() λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€.

count 값을 μ¦κ°€μ‹œν‚€κ³  ν™•μΈν•˜λŠ” κ°„λ‹¨ν•œ λ‘œμ§μž…λ‹ˆλ‹€.

μœ„μ—μ„œλ„ μ–˜κΈ°ν–ˆμ§€λ§Œ, ν”„λ‘œν† νƒ€μž… λΉˆμ—μ„œλŠ” @PreDestroyλŠ” μžλ™ ν˜ΈμΆœλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

 

메인 클래슀둜 κ°€λ³΄κ² μŠ΅λ‹ˆλ‹€.

첫 번째 PrototypeBean μΈμŠ€ν„΄μŠ€λ₯Ό κ°€μ Έμ˜€κ³ , addCount() 호좜둜 count 값을 1 μ¦κ°€μ‹œν‚΅λ‹ˆλ‹€.

그러고, getCount()κ°€ 1인지 ν™•μΈν•©λ‹ˆλ‹€.

 

두 번째 μΈμŠ€ν„΄μŠ€λ₯Ό λ‹€μ‹œ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ—μ„œ κ°€μ Έμ˜΅λ‹ˆλ‹€.

μƒˆλ‘œμš΄ 객체이기 λ•Œλ¬Έμ— count 값은 λ‹€μ‹œ 0λΆ€ν„° μ‹œμž‘ν•˜κ³ , addCount() ν›„μ—λŠ” count 값이 λ‹€μ‹œ 1이 λ©λ‹ˆλ‹€.

결둠은 pb1κ³Ό pb2λŠ” μ„œλ‘œ λ‹€λ₯Έ μΈμŠ€ν„΄μŠ€λΌλŠ” 것!

 

κ²°κ³Όλ₯Ό ν•œ 번 λ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

ν”„λ‘œν† νƒ€μž… 빈 직접 μš”μ²­ κ²°κ³Ό

잘 λ‚˜μ™”μŠ΅λ‹ˆλ‹€.

두 κ°œκ°€ μ„œλ‘œ λ‹€λ₯Έ μΈμŠ€ν„΄μŠ€(객체)λΌλŠ” 것을 λ°”λ‘œ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ΄λ²ˆμ—λŠ” clientBeanμ΄λΌλŠ” 싱글톀 빈이 μ˜μ‘΄κ΄€κ³„ μ£Όμž…μ„ ν†΅ν•΄μ„œ ν”„λ‘œν† νƒ€μž… λΉˆμ„ μ£Όμž…λ°›μ•„ μ‚¬μš©ν•˜λŠ” 예제λ₯Ό λ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

<β­μ‹±κΈ€ν†€μ—μ„œ ν”„λ‘œν† νƒ€μž… 빈 μ‚¬μš©β­>

μ‹±κΈ€ν†€μ—μ„œ ν”„λ‘œν† νƒ€μž… 빈 μ‚¬μš©1

πŸ‘‰πŸ» clientBean은 μ‹±κΈ€ν†€μ΄λ―€λ‘œ, 보톡 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆ 생성 μ‹œμ μ— ν•¨κ»˜ μƒμ„±λ˜κ³ , μ˜μ‘΄κ΄€κ³„ μ£Όμž…λ„ λ°œμƒν•©λ‹ˆλ‹€.

1. clientBean은 μ˜μ‘΄κ΄€κ³„ μžλ™ μ£Όμž…μ„ μ‚¬μš©ν•©λ‹ˆλ‹€. μ£Όμž… μ‹œμ μ— μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— ν”„λ‘œν† νƒ€μž… λΉˆμ„ μš”μ²­ν•©λ‹ˆλ‹€.

2. μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” ν”„λ‘œν† νƒ€μž… λΉˆμ„ μƒμ„±ν•΄μ„œ clientBean에 λ°˜ν™˜ν•©λ‹ˆλ‹€. ν”„λ‘œν† νƒ€μž… 빈의 count ν•„λ“œ 값은 0 μž…λ‹ˆλ‹€.

βœ”οΈμ΄μ œ clientBean은 ν”„λ‘œν† νƒ€μž… λΉˆμ„ λ‚΄λΆ€ ν•„λ“œμ— λ³΄κ΄€ν•©λ‹ˆλ‹€. (μ •ν™•νžˆλŠ” 참쑰값을 λ³΄κ΄€ν•©λ‹ˆλ‹€.)

μ‹±κΈ€ν†€μ—μ„œ ν”„λ‘œν† νƒ€μž… 빈 μ‚¬μš©2

πŸ‘‰πŸ» ν΄λΌμ΄μ–ΈνŠΈAλŠ” clientBean을 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μš”μ²­ν•΄μ„œ λ°›μŠ΅λ‹ˆλ‹€. μ‹±κΈ€ν†€μ΄λ―€λ‘œ 항상 같은 clientBean이 λ°˜ν™˜λ©λ‹ˆλ‹€.

3. ν΄λΌμ΄μ–ΈνŠΈAλŠ” clientBean.logic()을 ν˜ΈμΆœν•©λ‹ˆλ‹€.

4. clientBean은 prototypeBean의 addCount()λ₯Ό ν˜ΈμΆœν•΄μ„œ ν”„λ‘œν† νƒ€μž… 빈의 countλ₯Ό μ¦κ°€ν•©λ‹ˆλ‹€. count 값은 1이 λ©λ‹ˆλ‹€.

μ‹±κΈ€ν†€μ—μ„œ ν”„λ‘œν† νƒ€μž… 빈 μ‚¬μš©3

πŸ‘‰πŸ» ν΄λΌμ΄μ–ΈνŠΈBλŠ” clientBean을 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μš”μ²­ν•΄μ„œ λ°›μŠ΅λ‹ˆλ‹€. μ‹±κΈ€ν†€μ΄λ―€λ‘œ 항상 같은 clientBean이 λ°˜ν™˜λ©λ‹ˆλ‹€.

μ—¬κΈ°μ„œ μ€‘μš”ν•œ 점이 ν•˜λ‚˜ μžˆμŠ΅λ‹ˆλ‹€.

βœ”οΈclientBean이 내뢀에 κ°€μ§€κ³  μžˆλŠ” ν”„λ‘œν† νƒ€μž… λΉˆμ€ 이미 과거에 μ£Όμž…μ΄ λλ‚œ 빈 μž…λ‹ˆλ‹€.

βœ”οΈμ£Όμž… μ‹œμ μ— μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ— μš”μ²­ν•΄μ„œ ν”„λ‘œν† νƒ€μž… 빈이 μƒˆλ‘œ 생성이 된 것이고, μ‚¬μš©ν•  λ•Œλ§ˆλ‹€ μƒˆλ‘œ μƒμ„±λ˜λŠ” 것이 μ•„λ‹™λ‹ˆλ‹€.

5. ν΄λΌμ΄μ–ΈνŠΈBλŠ” clientBean.logic()을 ν˜ΈμΆœν•©λ‹ˆλ‹€.

6. clientBean은 prototypeBean의 addCount()λ₯Ό ν˜ΈμΆœν•΄μ„œ ν”„λ‘œν† νƒ€μž… 빈의 countλ₯Ό μ¦κ°€ν•©λ‹ˆλ‹€. μ›λž˜ count 값이 1 μ΄μ—ˆμœΌλ―€λ‘œ 2κ°€ λ©λ‹ˆλ‹€. (count κ°’ 1πŸ‘‰πŸ»2)

 

μ½”λ“œλ‘œ ν•œ 번 λ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ•„κΉŒ λ§Œλ“€μ—ˆλ˜ SingletonWithPrototypeTest1 클래슀λ₯Ό μˆ˜μ •ν•΄μ„œ μž‘μ„±ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

 

 

 

 


4. ν”„λ‘œν† νƒ€μž… μŠ€μ½”ν”„ - 싱글톀 빈과 ν•¨κ»˜ μ‚¬μš© μ‹œ Provider둜 문제 ν•΄κ²°

 

 

 

 

 

 

 

 


μ΄λ ‡κ²Œ 끝이 λ‚¬μŠ΅λ‹ˆλ‹€.

와아아 ν”„λ‘œμ νŠΈλ‘œ λ‹€μ‹œ λŒμ•„μ˜¬κ²Œμš”!

μ•ˆλ‡¨μ˜ΉπŸ˜„