일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 데이터 압축
- NoUniqueBeanDefinitionException
- Reading HttpServletRequest Multiple Times
- Unchecked Exception
- 상호 인증
- Java Rest
- java
- Graphql Client
- mTLS
- 개방 폐쇄 원칙
- AfterMapping
- requestheaderdto
- Checked Exception
- Srping MVC
- 바이트 절삭
- Sub Bytes
- Request Body 여러 번 사용
- Java Graphql
- graphql
- mapstruct
- Socket is closed
- Java Singleton
- HandlerMethodArgumentResolver
- tomcat jndi
- Open Close Principal
- WildFly
- Jndi DataSource
- 이중정렬
- try - with - resources
- Tomcat DBCP
- Today
- Total
Developer Sang Guy
Java Singleton 객체 구현 및 주의 사항 본문
스프링 공부하다가 Singleton에 대해서 알게되었다.
스프링에서는 몇몇 어노테이션 달아주면 IOC 컨테이너에 빈이 생성되며 스코프가 자동으로 싱글톤으로 적용된다.
하지만 스프링 프레임워크를 사용하지 않은 자바에서는 이런게 없으므로 평범한 객체를 싱글톤으로 변경하는 방법과 주의 사항을 적어보겠다.
그 전에 스코프에 대해서도 정리해보겠다.
스코프는 2종류가 있는데 하나는 싱글톤, 나머지 하나는 프로토 타입이다.
싱글톤 - 사용 할 때 마다동일한 인스턴스를 반환
프로토 타입 - 사용 할 때마다 새로운 객체를 생성 및 반환
싱글톤이 적용 된 SingletonClass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class SingletonClass {
/* static 으로 객체 1회 생성 */
private static SingletonClass instance = new SingletonClass();
/* 외부에서 해당 메서드로 객체 호출 */
public static SingletonClass getInstance( ) {
return instance;
}
/* 인스턴스 생성하지 못하게 하기 위해 private로 객체 선언 */
private SingletonClass() {
}
}
|
cs |
의외로 굉장히 간단하다.
해당 객체를 static 메서드로 선언하여 메모리에 적재한다.
이 후 getInstance 메서드를 사용하여 객체를 사용하며 new Instance를 막기위해 private로 선언한다.
위에는 애플리케이션 실행 시 메모리에 적재하는 방법이며 아래는 객체 사용 시 적재하는 방법이다.
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
31
32
|
public class SingletonClass {
/* static 으로 객체 1회 생성 */
private static SingletonClass instance = null;
private String str;
/* 외부에서 해당 메서드로 객체 호출 */
public static SingletonClass getInstance( ) {
if (instance == null) {
instance = new SingletonClass();
}
return instance;
}
/* 인스턴스 생성하지 못하게 하기 위해 private로 객체 선언 */
private SingletonClass() {
}
public void changeStr(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
|
cs |
싱글톤이 적용되지 않았을 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Main {
public static void main(String[] args) {
SingletonClass singletonClass1 = new SingletonClass();
SingletonClass singletonClass2 = new SingletonClass();
System.out.println(singletonClass1);
System.out.println(singletonClass2);
}
}
preSingleton.SingletonClass@4926097b
preSingleton.SingletonClass@762efe5d
|
cs |
싱글톤이 적용 되었을 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Main {
public static void main(String[] args) {
SingletonClass singletonClass1 = SingletonClass.getInstance();
SingletonClass singletonClass2 = SingletonClass.getInstance();
System.out.println(singletonClass1);
System.out.println(singletonClass2);
}
}
preSingleton.SingletonClass@4926097b
preSingleton.SingletonClass@4926097b
|
cs |
싱글톤 적용은 간단하지만 잘못 사용 된 싱글톤은 어마어마한 오류를 일으킬수 있다.
아래 소스로 예를 들어보겠다.
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
|
public class SingletonClass {
/* static 으로 객체 1회 생성 */
private static final SingletonClass instance = new SingletonClass();
private String str;
/* 외부에서 해당 메서드로 객체 호출 */
public static SingletonClass getInstance( ) {
return instance;
}
/* 인스턴스 생성하지 못하게 하기 위해 private로 객체 선언 */
private SingletonClass() {
}
public void changeStr(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Main {
public static void main(String[] args) {
SingletonClass singletonClass1 = SingletonClass.getInstance();
singletonClass1.changeStr("Test 1");
SingletonClass singletonClass2 = SingletonClass.getInstance();
singletonClass2.changeStr("Test 2");
System.out.println(singletonClass1.getStr());
}
}
|
cs |
SingletonClass를 사용하여 특정 문자를 변환하고 변환 된 문자를 가져오려한다.
일반적으로 생각하면 main 메서드의 결과 값은 Test 1을 생각하지만 실제 결과는 반대다.
결과 :
1
2
|
Test 2
|
cs |
이유는 간단하다.
SingletonClass는 싱글톤으로 생성되어 언제나 같은 인스턴스를 반환한다.
singletonClass1에서는 Test 1 이라는 문자열을 세팅하여 전역변수 str=Test 1이 되었지만
이 후 진행 된 singletonClass2에서 str=Test 2로 변경되었다.
이 후 getStr()을 사용하여 전역변수 str을 값을 가지고 오다보니 당연히 Test 2가 반환되었다.
위 상황과 같이 Singleton이 적용 된 객체에서 전역변수와 같이 객체 내에서 공유되는 값을 변환하거나 외부로 반환하는 것은 매우 치명적인 오류를 일으킬 수 있다.
예를 들어 로그인을 하여 저장소에서 회원 정보를 가져오는 객체가 Single톤이며 해당 정보가 전역변수와 같이 객체 내에 공유되는 변수로 사용 될 시 내가 로그인에 사용한 계정 정보가 아닌 내 다음 번에 로그인 시도를 한 엉뚱한 사람의 계정으로 로그인이 될 수도 있다.
싱글톤은 항상 무상태(stateless)로 설계해야 한다는 것을 잊지말자
'Java' 카테고리의 다른 글
데이터 압축 (0) | 2022.05.26 |
---|---|
[Java]NonStaticInnerClass vs StaticInnerClass (0) | 2022.05.18 |
Java Graphql Client 구현 (0) | 2022.03.30 |
Java Http Rest 통신 소스 (0) | 2022.01.05 |
OCP (Open Close Principal) 개방 폐쇄 원칙 (0) | 2021.05.14 |