티스토리 뷰
Thread Local은 자바에서 제공해주는 멀티 스레드 환경에서 각각의 스레드에게 별도의 자원을 제공함으로써 공유되는 서비스에서 별도의 자원에 접근하게끔 하여 각각의 스레드가 각각의 상태를 가질 수 있도록 도와주고 있습니다.
실제로 Thread Local은 Spring진영에서 유용하게 쓰이고 있습니다. 대표적으로 RequestAttribute하고 SecurityContext가 존재합니다. 그렇다면 스프링에서 유용하게 쓰이는지 알아봅시다.
예를들어 로그인 기능이 존재하고 생각해봅시다. A와 B가 각각 클라이언트 요청을 통해 로그인이 필요한 상품 구매 시스템을 이용한다고 생각해 봅시다.
- Thread 1 - 로그인 정보를 갖고 상품 구매 요청
- 싱글톤 서비스 - 요청으로 들어온 로그인 정보 검증 및 저장
- Thread 2 - 다른 사용자가 잘못된 정보를 갖고 상품 구매 요청
- 싱글톤 서비스 - 이미 로그인 정보가 저장되어 있기 때문에 인증 정보가 존재하는지 확인 하지 않고 그대로 다음 프로세스를 이어나간다.
Thread 1의 로그인 정보가 이미 서비스에 전달 되었기 때문에 서비스에는 아직 로그인 정보가 남겨져 있기 때문에 이런 현상이 발생했습니다. 그래서 Thread 2는 잘못된 정보를 들고있었음에도 불구하고 서비스에 로그인 정보가 남아있기 때문에 그대로 다음 프로세스를 이어나갈 수 있습니다.
Thread Local은 이러한 현상을 막아줍니다. 어떻게 막아주는지 내부를 살펴보겠습니다.
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
ThreadLocal 클래스에 get() 메소드와 getMap 메소드입니다. get 동작 방식을 보면 currentThread() 메소드로 현재 스레드를 호출하고 스레드에 가 참조하고 있는 인스턴스 변수인 threadLocals라는 변수를 받아옵니다. threadLocals는 ThreadLocalMap 타입의 인스턴스이며 ThreadLocalMap은 key-value 형태의 데이터 저장소 입니다. 그렇기 때문에 현재 스레드 기준으로 값을 가져올 수 있는 것입니다.
그리고 스프링은 이러한 ThreadLocal의 장점을 이용하여 SecurityContext에 회원 인증 정보를 저장할 때 쓰거나 HttpServletRequest를 조회할 수 있는 RequestContext에도 사용하여 싱글톤 서비스를 이용하더라도 동시성 처리를 하더라도 외부에서 받아온 정보가 문제없이 동작하는 것입니다.
하지만 이도 주의할점이 있습니다. WAS에서는 Thread Pool에 Thread를 보관하여 애플리케이션이 기본적으로 이 Thread Pool에 Thread를 사용하게 됩니다. 이 때 Thread는 사용하고 반납하는 개념이기 때문에 ThreadLocal 안에 정보를 지워주지 않으면 다른 요청이 해당 Thread를 할당 받았을 때 전에 사용하던 정보가 담겨져 있을 수 있습니다.
그리고 이를 제대로 처리하지않는다면 외부에서 이를 이용하여 정보를 마음대로 위조 또는 변조할 수 있는 위험한 상황이 될 수 있습니다.
실제로 Spring 진영에서는 이를 방지하고자 Security에서는 cleanContext() RequestContext에서는 resetRequestAttributes()라는 메서드로 매번 초기화 해주고 있습니다.
Ref.
https://catsbi.oopy.io/3ddf4078-55f0-4fde-9d51-907613a44c0d
'Spring Framwork & JPA' 카테고리의 다른 글
AspectJ 안에서 AOP로 동작하는 Transactional을 사용하면 무슨일이 일어날까? (1) | 2023.03.25 |
---|---|
Redis INCR을 이용한 분산환경에서의 동시성 제어하기 (0) | 2023.02.13 |
[Redis] redis에서 get 연산이 일어나는 로직에 Transactional을 건다면? (0) | 2023.01.03 |
많은 외부 API를 호출해야 하는 상황에서 성능 개선 (with. webClient) (0) | 2023.01.02 |
Pagination 전략에 대해서 (Page 인터페이스 커스텀하기) (0) | 2022.08.04 |
- Total
- Today
- Yesterday
- 자바
- CS
- MySQL
- 코드
- 프로그래밍
- 면접
- JPA
- Spring
- 취준
- IT
- 게시판
- 프로젝트
- 면접준비
- Kotlin
- DevOps
- java
- 면접 준비
- 동시성
- 인터뷰
- 취업준비
- 개발
- 취업
- thread
- swarm
- Redis
- 코딩
- 개발자
- DB
- docker
- 백엔드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |