일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 플라이웨이트
- Proxy Patter
- deleteById
- 트랜잭션
- 데이터베이스
- Connection Pool
- @Valid
- 이펙티브 자바
- NotEmpty
- @SpyBean
- java
- Web
- Effetive Java
- SQL 삽입 공격
- springboot
- restTemplate
- JPA
- Firebase
- Item04
- Service Locator
- FCM
- NotBlank
- 디자인 패턴
- db
- Effective Java
- Service Locator 패턴
- multi module
- @ControllerAdvice
- Spring Boot
- @MockBean
- Today
- Total
NoTimeForDawdling
Item03 private 생성자나 열거 타입으로 싱글턴임을 보증하라 본문
싱글턴(Singleton)
-
싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말합니다.
-
단순히 함수를 사용하기 위한 유틸, 로깅, 설계상 유일해야 하는 시스템 컴포넌트를 보통 싱글턴 인스턴스로 관리합니다.
-
클래스를 싱글톤으로 만들면 이를 사용하는 클라이언트를 테스트하기가 어려워질 수 있습니다.
싱글턴 만드는 방법
1. public static final 필드 방식
public class Elvis1 {
public static final Elvis1 INSTANCE = new Elvis1();
private Elvis1() {
}
}
- public static final Elvis1 INSTANCE = new Elvis1() 은 static 영역이 로딩될 때 딱 1번만 호출됩니다.
-
해당 클래스가 싱글턴임이 API에 명백히 들어납니다.
-
final이니 절대로 다른 객체를 참조할 수 없으며, 굉장히 간결합니다.
2. 정적 팩터리 방식
public class Elvis2 {
private static final Elvis2 INSTANCE = new Elvis2();
private Elvis2() {
}
public static Elvis2 getInstance() {
return INSTANCE;
}
}
- 이 방법은 정적 팩터리 메서드를 public static 멤버로 제공합니다.
-
Elvis2.getInstace() 는 항상 같은 객체의 참조를 반환하므로 싱글턴을 보장해줍니다.
-
이 방식이 첫 번째 방식에 비해 API 변경에 매우 유연합니다.
-
메서드 레퍼런스로 Elvis2::getInstance 처럼 사용이 가능합니다.
역직렬화 시 싱글턴 깨짐
-
위 두 방법 모드 역직렬화 할 때 같은 타입의 인스턴스가 여러개 생길 수 있습니다.
-
이미 직렬화된 Evlis 를 다시 역직렬화 할 때, private static final Elvis INSTANCE 이라면 여러 인스턴스가 생길 수 있는 것입니다.
-
해결 방법으로는 transient 키워드를 추가하고, readResolve()를 구현해서 transient Elvis INSTANCE를 반환하도록 해야합니다.
public class Elvis3 implements Serializable {
private static final transient Elvis3 INSTANCE = new Elvis3();
public static Elvis3 getInstance() {
return INSTANCE;
}
public Object readResolve() {
// 진짜 Elvis3를 반환하고, 가짜 Elvis3 는 GC가 처리한다.
return INSTANCE;
}
}
직렬화 역직렬화 알아가기
-
직렬화 : JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 byte 형태로 변환하는 기술
-
역직렬화 : 직렬화된 byte 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태
-
transient
-
Serialize하는 과정에서 제외하고 싶은 경우 선언하는 키워드
-
패스워드와 같은 보안정보가 직렬화 과정에서 제외하고 싶은 경우 적용
-
-
readResolve() : 역직렬화 하는 과정에 호출
-
클래스의 멤버변수가 serializable 하지않을 경우, 이 멤버변수를 직렬화/역직렬화 해주기 위해 호출
-
3. enum(가장 바람직한 방법)
public enum Elvis {
INSTANCE;
}
-
1번 방식과 비슷하지만, 더 간결하고, 추가 노력 없이 직렬화 할 수 있습니다.
-
원소가 하나뿐인 열거 타입의 싱글톤을 만드는 가장 좋은 방법입니다.
-
만들려는 싱글톤이 Enum외의 클래스를 상속해야 한다면 사용할 수 없습니다.
'Effective Java' 카테고리의 다른 글
Item06 불필요한 객체 생성을 피하라 (0) | 2021.05.27 |
---|---|
Item05 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2021.05.25 |
Item04 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2021.03.31 |
Item02 생성자 매개변수가 많은 경우에 빌더 사용을 고려해 볼 것 (0) | 2021.03.04 |
Item01 생성자 대신 정적 팩토리 메서드를 고려하라 (0) | 2021.03.02 |