JiwonDev

ν† λΉ„μ˜μŠ€ν”„λ§#2 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬μ™€ 였브젝트 μŠ€μ½”ν”„

by JiwonDev

2021.08.14 - [Backend/Spring Core] - ν† λΉ„μ˜ μŠ€ν”„λ§#1 μ˜€λΈŒμ νŠΈμ™€ μ˜μ‘΄κ΄€κ³„

 

μ•žμ—μ„œ μ–ΈκΈ‰ν•œ 이 λ‚΄μš©μ— λŒ€ν•΄μ„œ 쑰금 더 μžμ„Έν•˜κ²Œ μ•Œμ•„λ³΄μž.

 


# 였브젝트의 동일성과 동등성

'μžλ°”μ—μ„œ 두 개의 μ˜€λΈŒμ νŠΈκ°€ 같은가?' λΌλŠ” 말은 μ£Όμ˜ν•΄μ„œ μ‚¬μš©ν•΄μ•Όν•œλ‹€. 동일성(Identity)와 동등성(Equality)의 차이가 있기 λ•Œλ¬Έμ΄λ‹€.

  • 동일성 비ꡐ(==, Identity)λŠ” κ°€λ₯΄ν‚€κ³  μžˆλŠ” 객체가 λ™μΌν•œ κ²½μš°μ— μ‚¬μš©ν•˜λŠ” 말이닀.
  • 동등성 비ꡐ(.equal() .hashtag(), Equality)λŠ” 객체가 가진 κ°’, 정보가 λ™μΌν•œ 경우 μ‚¬μš©ν•˜λŠ” 말이닀.

μ˜€λΈŒμ νŠΈκ°€ λ™μΌν•˜λ©΄ 동등성을 λ§Œμ‘±ν•˜μ§€λ§Œ, λ°˜λŒ€λ‘œ λ™λ“±ν•˜λ‹€κ³  ν•΄μ„œ λ™μΌν•œ κ°μ²΄μž„μ„ 보μž₯ν•  순 μ—†λ‹€. 이해가 μ•ˆλœλ‹€λ©΄ μ•„λž˜κΈ€μ„ μ°Έκ³ ν•΄λ³΄μž. 2021.07.27 - [κΈ°λ³Έ 지식/Java 기본지식] - .equals와 .hashCode()λŠ” 항상 ν•¨κ»˜ μ˜€λ²„λΌμ΄λ”©ν•΄μ•Όν•œλ‹€.

 

.equals와 .hashCode()λŠ” 항상 ν•¨κ»˜ μ˜€λ²„λΌμ΄λ”©ν•΄μ•Όν•œλ‹€.

Object λ©”μ„œλ“œμ— μžˆλŠ” .hashCode() λ©”μ„œλ“œλŠ” ν•΄λ‹Ή 객체의 μ£Όμ†Œκ°’μ„ μ΄μš©ν•˜μ—¬ λ§Œλ“  객체만의 κ³ μœ ν•œ μ •μˆ˜ 값을 가진닀. equals()λ₯Ό μ˜€λ²„λΌμ΄λ”© ν•  λ•Œμ—λŠ” λ°˜λ“œμ‹œ hashCode()도 λ™μΌν•œ κ²°κ³Όλ₯Ό 내도둝 ν•¨κ»˜ 였

jiwondev.tistory.com

 


# μŠ€ν”„λ§μ—μ„œμ˜ 빈 객체

μ»¨ν…Œμ΄λ„ˆ (Object Factory)μ—μ„œ 같은 객체λ₯Ό μƒμ„±ν•˜κ²Œ 되면 두 객체가 가진 값은 κ°™μ§€λ§Œ, μ‹€μ œ λ“±λ‘λœ κ°μ²΄λŠ” λ‹€λ₯Έ 객체이닀. 즉 '동등성'은 λ§Œμ‘±ν•˜λ‚˜ '동일성'은 λ§Œμ‘±ν•˜μ§€ μ•ŠλŠ”λ‹€. 객체λ₯Ό 생성 ν•  λ•Œλ§ˆλ‹€ μ€‘λ³΅ν•΄μ„œ λ§Œλ“€κ²Œλœλ‹€.

DaoFactory factory = new DaoFactory(); // AppConfig 객체λ₯Ό μ˜λ―Έν•œλ‹€.

// 이 두 κ°μ²΄λŠ” λ‹€λ₯΄λ‹€.
UserDao dao1 = factory.userDao();
UserDao dao2 = factory.userDao();

// my.package.UserDao@118f375
// my.package.UserDao@117A8bd
System.out.println(dao1 + "\n" + dao2);

 

μŠ€ν”„λ§μ—μ„œλŠ” μ΄λŸ¬ν•œ 쀑볡(λ‚­λΉ„)λ₯Ό λ§‰κΈ°μœ„ν•΄ 객체λ₯Ό μ‹±κΈ€ν†€μœΌλ‘œ λ“±λ‘ν•œλ‹€.

// Object Factory 객체λ₯Ό μŠ€ν”„λ§ μ„€μ •νŒŒμΌλ‘œ λ„˜κ²¨μ£Όμ–΄, μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλ₯Ό μ‚¬μš©ν•˜λŠ” 방법
ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);

// κ·Έλ ‡λ‹€λ©΄ 이 두 객체도 동일성은 λ§Œμ‘±ν•˜μ§€ λͺ»ν•˜λŠ” 걸까?
UserDao dao1 = context.getBean("userDao", UserDao.class);
UserDao dao2 = context.getBean("userDao", UserDao.class);

// λ†€λžκ²Œλ„ 동일성을 λ§Œμ‘±ν•œλ‹€. λͺ‡ 개λ₯Ό μƒμ„±ν•˜λ˜ λ™μΌν•œ ν•˜λ‚˜μ˜ 객체만 μƒμ„±ν•˜κ³ , μ°Έμ‘°ν•œλ‹€.(싱글톀)
// my.package.UserDao@ee22f7
// my.package.UserDao@ee22f7
System.out.println(dao1 + "\n" + dao2);

 


# 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬λ‘œμ„œ ApplicationContext

μŠ€ν”„λ§μ—μ„œ μ‚¬μš©ν•˜λŠ” μ»¨ν…Œμ΄λ„ˆ, Application ContextλŠ” μš°λ¦¬κ°€ μ•žμ—μ„œ λ§Œλ“€μ—ˆλ˜ Object Factory와 λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€. ν•˜μ§€λ§Œ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆλŠ” 이와 λ™μ‹œμ— 싱글톀을 μ €μž₯ν•˜κ³  κ΄€λ¦¬ν•˜λŠ” 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬(singleton registry) 이기도 ν•˜λ‹€.

 

μŠ€ν”„λ§μ€ ν•„μš”μ— 따라 λ”°λ‘œ μ„€μ •ν•˜λŠ” 게 μ•„λ‹ˆλΌλ©΄, 기본적으둜 μƒμ„±ν•˜λŠ” 빈 κ°μ²΄λŠ” μ „λΆ€ μ‹±κΈ€ν†€μœΌλ‘œ λ§Œλ“ λ‹€. λ””μžμΈ νŒ¨ν„΄μ—μ„œ λ‚˜μ˜€λŠ” 싱글톀 νŒ¨ν„΄κ³Ό λΉ„μŠ·ν•œ κ°œλ…μ΄μ§€λ§Œ, κ΅¬ν˜„λ°©λ²•μ€ ν™•μ—°νžˆ λ‹€λ₯΄λ‹€.

 


@ μ½”λ“œλ‘œ κ΅¬ν˜„ν•œ μ‹±κΈ€ν†€μ˜ ν•œκ³„

근데 μ΄λ ‡κ²Œ λ°”μ΄νŠΈμ½”λ“œλ₯Ό μ‘°μž‘ν•˜λ©΄μ„œκΉŒμ§€ 싱글톀을 κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” μ΄μœ λŠ” λ¬΄μ—‡μΌκΉŒ? κ·Έ μ΄μœ λŠ” μŠ€ν”„λ§μ€ νƒœμƒμ μœΌλ‘œ μ„œλ²„(μ›Ή μ„œλ²„)에 주둜 μ‚¬μš©λ˜λŠ” ν”„λ ˆμž„μ›Œν¬μ΄κΈ° λ•Œλ¬Έμ΄λ‹€. μŠ€ν”„λ§μ΄ 처음 μ„€κ³„λ˜μ—ˆλ˜ λŒ€κ·œλͺ¨ μ„œλΉ„μŠ€λ₯Ό μ²˜λ¦¬ν•˜λŠ” μ„œλ²„ν™˜κ²½μ€ μ΄ˆλ‹Ή μˆ˜μ‹­, μˆ˜λ°±λ²ˆμ— 이λ₯΄λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ„ μ²˜λ¦¬ν•œλ‹€. κ·Έ ν•˜λ‚˜μ˜ μš”μ²­μ„ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ [데이터 μ—‘μ„ΈμŠ€(DB) 객체, μ„œλΉ„μŠ€ 객체, 핡심 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 객체]λ“± μˆ˜λ§Žμ€ 객체듀이 μ°Έμ—¬ν•˜λŠ” 계측적인 ꡬ쑰둜 μ΄λ£¨μ–΄μ§€λŠ”κ²Œ λŒ€λΆ€λΆ„μ΄λ‹€. 

 

맀번 ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ΄ 올 λ•Œλ§ˆλ‹€ 각 λ‘œμ§μ„ λ‹΄λ‹Ήν•˜λŠ” 객체λ₯Ό μƒˆλ‘œ λ§Œλ“ λ‹€κ³  μƒκ°ν•΄λ³΄μž. μ΄ˆλ‹Ή 500개의 μš”μ²­μ΄ λ“€μ–΄μ˜¨λ‹€λ©΄ 2500개의 μƒˆλ‘œμš΄ 객체가 μƒμ„±λœλ‹€. 1뢄이면 μ‹­λ§Œκ°œ, ν•œμ‹œκ°„μ΄λ©΄ μ„œλ²„μ— 900만개의 μ˜€λΈŒμ νŠΈκ°€ μƒμ„±λ˜κ³  μ‚¬μš©λ  것이닀. 아무리 JVMκ³Ό GC의 κΈ°λŠ₯이 μ’‹μ•„μ‘Œλ‹€κ³  ν•œλ“€, 객체λ₯Ό μƒμ„±ν•˜κ³  μ†Œλ©Έμ‹œν‚€λŠ” 과정은 μ—°μ‚° λΉ„μš©μ΄ λΉ„μ‹Ό μž‘μ—…μ΄λ‹€. κ·Έλž˜μ„œ μ—¬λŸ¬ μŠ€λ ˆλ“œμ—μ„œ ν•˜λ‚˜μ˜ 객체λ₯Ό κ³΅μœ ν•΄ λŒλ €μ“°λ„λ‘ 싱글톀을 κ΅¬ν˜„ν•˜λŠ” 것이닀.

 

λ‹€λ§Œ μ½”λ“œλ‘œλ„ 싱글톀을 κ΅¬ν˜„ν•  μˆ˜λŠ” μžˆλ‹€. ν•˜μ§€λ§Œ μ‹€μ œ μ„œλΉ„μŠ€μ—μ„œ μ‚¬μš©ν•˜κΈ°μ—λŠ” μ•„λž˜μ™€ 같은 ν•œκ³„μ μ΄ μžˆλ‹€.

public class DoubleLockSingleton {
    // λ‹¨μˆœν•œ 싱글톀 κ΅¬ν˜„ 방법
    private static final Singleton instance = new Singleton();
    
    // private μƒμ„±μžλ₯Ό μ΄μš©ν•˜μ—¬ 같은 객체가 쀑볡 μƒμ„±λ˜λŠ” 것을 λ§‰μŒ.
    private Singleton(){}
 
    public static Singleton getInstance(){
        // λ©€ν‹°μŠ€λ ˆλ“œμ—μ„œ 싱글톀 객체 μƒμ„±μ˜ Thread-safety 보μž₯
        if(instance == null){
            synchronized (Singleton.class) {
                if(instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}
  • private μƒμ„±μž λ•Œλ¬Έμ— 객체λ₯Ό 상속할 수 μ—†λ‹€. μ„œλΉ„μŠ€ 객체에 λ‹€ν˜•μ„±μ„ μ μš©ν•˜κΈ° μ–΄λ ΅λ‹€.
  • μ‹€μ œ 객체가 μ•„λ‹Œ ν…ŒμŠ€νŠΈμš© 객체(mock)λ₯Ό μ‚¬μš©ν•˜κΈ° μ–΄λ ΅λ‹€. 즉 ν…ŒμŠ€νŠΈ ν™˜κ²½κ΅¬μ„±μ΄ μ–΄λ €μ›Œμ§„λ‹€.
  • λΆ„μ‚°λœ μ„œλ²„ν™˜κ²½μ—μ„œ 싱글톀이 ν•˜λ‚˜λ§Œ λ§Œλ“€μ–΄μ§€λŠ” 것을 보μž₯ν•˜μ§€ λͺ»ν•œλ‹€. (μ„œλ²„μ™€ JVM이 μ—¬λŸ¬κ°œμ΄λ‹€)
  • 싱글톀 객체가 'μ „μ—­ λ³€μˆ˜'처럼 μ‚¬μš©λ  수 μžˆλŠ” κ°€λŠ₯성을 κ°€μ§€κ³ μžˆλ‹€.  μ΄λŸ¬ν•œ 방식은 side-effectλ₯Ό μœ λ°œν•œλ‹€.

κ·Έλž˜μ„œ μŠ€ν”„λ§μ€ λ°”μ΄νŠΈμ½”λ“œ μ‘°μž‘μ„ 톡해 직접 싱글톀 ν˜•νƒœμ˜ 였브젝트λ₯Ό λ§Œλ“€κ³  κ΄€λ¦¬ν•˜λŠ” κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ”λ°, 이λ₯Ό 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬λΌκ³  λΆ€λ₯Έλ‹€. 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬λŠ” μ½”λ“œ μƒμ—μ„œ static λ©”μ„œλ“œμ™€ private μƒμ„±μžλ₯Ό μ΄μš©ν•΄μ•Όν•˜λŠ” 비정상적인 싱글톀 ν΄λž˜μŠ€κ°€ μ•„λ‹ˆλΌ, ν‰λ²”ν•œ μžλ°” 클래슀λ₯Ό 싱글톀 객체둜 μ‚¬μš©ν•  수 있게 λ§Œλ“€μ–΄μ€€λ‹€.

 

싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬λŠ” 싱글톀 νŒ¨ν„΄κ³Ό 달리 μžλ°”μ˜ 객체지ν–₯적인 섀계 λ°©μ‹μ΄λ‚˜ μ½”λ“œλ₯Ό ν™œμš©ν•˜λŠ”λ° μ•„λ¬΄λŸ° μ œμ•½μ΄ μ—†λ‹€λŠ” 큰 μž₯점이 μžˆλ‹€. λ‹€λ§Œ '싱글톀' νŒ¨ν„΄μ΄ κ°€μ§€λŠ” μœ„ν—˜μ„±μ€ 변함이 없기에, μ£Όμ˜ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 것을 잊으면 μ•ˆλœλ‹€.

 


@ 주의! 싱글톀과 였브젝트 μƒνƒœ

싱글톀은 λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ΄λΌλ©΄ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— μ ‘κ·Όν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€. λ”°λΌμ„œ '객체'κ°€ μƒνƒœ 값을 κ°€μ Έμ„œλŠ” μ•ˆλœλ‹€. μƒνƒœ 데이터λ₯Ό 가지고 μžˆμ§€ μ•ŠλŠ” Stateless λ°©μ‹μœΌλ‘œ 싱글톀을 μ‚¬μš©ν•΄μ•Όν•œλ‹€.

 

더 μ‰½κ²Œ λ§ν•˜λ©΄ 싱글톀 였브젝트의 μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λ₯Ό μˆ˜μ •ν•˜λŠ” μž‘μ—…μ€ 맀우 μœ„ν—˜ν•˜λ‹€λŠ” 말이닀. μ—¬λŸ¬ μŠ€λ ˆλ“œμ—μ„œ μ‚¬μš©λ  κ°€λŠ₯성이 μžˆκΈ°μ— Thread-Safetyν•˜μ§€ μ•Šλ‹€. 더 큰 λ¬Έμ œλŠ” μŠ€ν”„λ§μ—μ„œ 싱글톀 λ ˆμ§€μŠ€νŠΈλ¦¬λ₯Ό 톡해 κ΄€λ¦¬ν•΄μ£Όλ‹€λ³΄λ‹ˆ, κ°œλ°œμžκ°€ '싱글톀 객체'λΌλŠ” 사싀을 잊고 μƒνƒœλ₯Ό μ €μž₯ν•  수 μžˆλ‹€λŠ” μœ„ν—˜μ„±μ΄ μžˆλ‹€.

 

λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ μ΄λŸ¬ν•œ 였λ₯˜κ°€ λ°œμƒν•˜κ²Œλ˜λ©΄, κ·Έ 였λ₯˜λ₯Ό μž‘λŠ” 것은 상상 μ΄μƒμœΌλ‘œ μ–΄λ ΅λ‹€. μ‚¬μš©μžκ°€ λ‘œκ·ΈμΈμ„ ν–ˆλŠ”λ° λ‹€λ₯Έμ‚¬λžŒμ˜ 데이터가 λ³΄μ΄λŠ” 상황이라면, μ–΄λ””μ„œλΆ€ν„° μ–΄λ–€ μ½”λ“œλ₯Ό λ””λ²„κΉ…ν•΄μ•Όν• κΉŒ μƒμƒν•΄λ³΄μž. 정말 λ‹΅ μ—†λŠ” 상황이고, μ‹€μ œ ν˜„μ—…μ—μ„œλ„ μ’…μ’… λ°œμƒν•˜λŠ” 일이기도 ν•˜λ‹€. κ·ΈλŸ¬λ‹ˆ 제발 μŠ€ν”„λ§ 빈 객체λ₯Ό μ‚¬μš©ν•  λ•Œ 기본값이 싱글톀 κ°μ²΄μž„μ„ μžŠμ§€λ§κ³  μ£Όμ˜ν•΄μ„œ 'Stateless'ν•˜κ²Œ μ‚¬μš©ν•˜λ„λ‘ ν•˜μž.

 

 

@ 싱글톀이 μ•„λ‹Œ 빈 객체

μŠ€ν”„λ§μ—μ„œ κ΄€λ¦¬ν•˜λŠ” 였브젝트, 즉 빈이 μƒμ„±λ˜κ³  μ‘΄μž¬ν•˜κ³  μ μš©λ˜λŠ” λ²”μœ„λ₯Ό μŠ€ν”„λ§μ—μ„œλŠ” 빈의 μŠ€μ½”ν”„(Scope)라고 λΆ€λ₯Έλ‹€. κΈ°λ³Έ 값인 싱글톀 μŠ€μ½”ν”„λŠ” μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆκ°€ μ‹€ν–‰λ˜λŠ” μ‹œμ μ— μƒμ„±λ˜κ³ , μ’…λ£Œλ˜λŠ” μ‹œμ μ— μ†Œλ©Έλœλ‹€.

 

λ‹€λ§Œ ν•„μš”μ— λ”°λΌμ„œλŠ” 싱글톀 μ™Έμ˜ λ‹€λ₯Έ μŠ€μ½”ν”„λ₯Ό κ°€μ§ˆ 수 μžˆλ‹€.

  • prototype μŠ€μ½”ν”„λŠ” 싱글톀 μŠ€μ½”ν”„μ™€ 달리 λΉˆμ„ μš”μ²­ν•  λ•Œ λ§ˆλ‹€ μƒˆλ‘œμš΄ 객체λ₯Ό λ§Œλ“€μ–΄μ€€λ‹€. 
  • request μŠ€μ½”ν”„λŠ” HTTP μš”μ²­μ΄ 왔을 λ•Œ 빈이 μƒμ„±λ˜κ³ , μš”μ²­μ΄ 끝났을 λ•Œ 빈이 λ°˜ν™˜λœλ‹€.
  • session μŠ€μ½”ν”„λŠ” μ›Ή μ„Έμ…˜κ³Ό μœ μ‚¬ν•˜κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€.

 

λ‹€λ§Œ 이 λ‚΄μš©μ€ μŠ€ν”„λ§μ— λŒ€ν•œ κΈ°μ΄ˆμ§€μ‹μ΄ μžˆμ–΄μ•Ό μ΄ν•΄ν•˜κΈ° μ‰¬μš°λ―€λ‘œ, λ‚˜μ€‘μ— μŠ€μ½”ν”„λ“€μ„ λ”°λ‘œ 닀루도둝 ν•˜κ² λ‹€.

2021.08.03 - [Backend/Spring Core] - #11 빈 μŠ€μ½”ν”„(+Provider, ν”„λ‘μ‹œ λͺ¨λ“œ)

 

#11 빈 μŠ€μ½”ν”„(+Provider, ν”„λ‘μ‹œ λͺ¨λ“œ)

μ•žμ—μ„œ μš°λ¦¬λŠ” μŠ€ν”„λ§ λΉˆμ€ μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ˜ μ‹œμž‘κ³Ό ν•¨κ»˜ μƒμ„±λ˜κ³ , μ»¨ν…Œμ΄λ„ˆκ°€ μ’…λ£Œλ  λ•Œ κΉŒμ§€ μœ μ§€λœλ‹€κ³  ν•™μŠ΅ν–ˆλ‹€. μ΄λŠ” μŠ€ν”„λ§ 빈이 기본적으둜 '싱글톀 μŠ€μ½”ν”„'둜 μƒμ„±λ˜κΈ° λ•Œλ¬Έμ΄λ‹€. μ—¬

jiwondev.tistory.com

 

λΈ”λ‘œκ·Έμ˜ 정보

JiwonDev

JiwonDev

ν™œλ™ν•˜κΈ°