스레드의 차단은 스레드가 작업이 완료될 때까지 다른 작업을 수행하지 못하고 기다리는 상태를 뜻함.
스레드 차단의 발생 상황
I/O작업 : 파일을 읽거나 쓰거나, 네트워크를 통해 데이터를 전송하거나 받는 등의 작업을 수행할 때 발생 (스레드는 데이터가 읽혀지거나 쓰여질 때까지차단됨)
동기적인 작업 : 다른 스레드가 완료될 때까지 기다리는 경우 (스레드 A가 스레드 B가 완료될 때까지 기다리는 상황이라면, 스레드 A는 스레드 B가 작업을 완료할 때까지 차단) 스레드를 메서드로 빗대어 예시를 들어보자면 위와 같이 작성되었을 경우, A 메서드 시작 > A 메서드 차단 > B 메서드 시작 > B 메서드 종료 > A 메서드 종료가 된다.
락(Lock) 획득 : 스레드가 특정 락을 획독하기 위해 대기하는 경우 (다른 스레드가 해당 락을 해제할 때까지 스레드는 차단 상태)
범용 고유 식별자라는 뜻으로 네트워크상에서 중복되지 않는 ID를 만들기 위한 표준 규약이다.
128비트 길이의 값으로 표현되는 식별자로, 전 세계적으로 고유하게 유지되도록 설계되었다.
UUID의 구성
UUID는 하이픈(-)으로 구분된 36자리의 16진수 숫자로 표현된다.
123e4567-e89b-12d3-a456-426655440000
UUID의 사용 용도
데이터베이스의 레코드 식별자
세션 식별자
파일 이름
객체 식별자
소프트웨어 구성 요소 식별자
나는 S3에 사진을 저장할 때 이름의 중복을 피하고자 이용하게 됐다.
UUID의 장점
고유성 : 전 세계적으로 고유한 값을 보장
분산성 : 중앙 등록 기관 없이 생성이 가능
무작위성 : 충돌 가능성이 매우 낮음
간단성 : 생성 및 사용이 비교적 간단
UUID의 구성 깊게 보기
위와 같이 UUID는 5개의 필드로 구성된다.
time_low (4바이트) - UUID가 생성된 시간의 하위 32비트 - 16진수 표현
time_mid (2바이트) - UUID가 생성된 시간의 중간 16비트 - 16진수 표현
time_hi_and_version (2바이트) - UUID가 생성된 시간의 상위 12비트와 UUID 버전을 나타냄 - 상위 4비트는 UUID의 버전 (가장 많이 사용되는 것은 [1] 타임스탬프 기반과 [4] 랜덤 생성) - 하위 12비트는 시간의 상위 12비트 - 16진수 표현
clock_seq_hi_and_res (2바이트) - UUID를 생성한 시스템 클럭의 시퀀스 번호의 상위 3비트와 예약된 3비트 - 상위 3비트는 시퀀스 번호의 상위 3비트 - 하위 3비트는 예약된 비트 - 16진수 표현
node (6바이트) - UUID를 생성한 시스템의 고유 식별자 - 48비트로 표현 - MAC 주소와 같은 네트워크 어드레스로 생성되거나 임의로 생성 됨
refreshToken을 이용해 accessToken을 발행하는 로직을 구현 하던 도중..
서블릿에서의 에러가 발생
JwtAuthenticationFilter의 doFilterInternal 메서드 내부의 로직 때문에 생긴 에러이다.
doFilterInternal 로직 중 accessToken을 확인해 만료가 됐다면 refreshToken 메서드(서비스)로 연결이 된다.
해당 서비스단 내부에서 새 토큰의 발행을 돕고, 그때 refreshToken 역시 만료가 됐다면 커스텀익셉션인 UserException을 발생시켜 GlobalExceptionHandler를 통해 처리가 되는 로직이다.
그 과정에서 위의 문제가 발생했다.
문제가 발생하는 로직
이유는 ?
기존의 GlobalExceptionHandler로 처리 되던 에러들은 doFilterIntenal을 벗어나 로직상에서 문제가 발생 됐기에 처리가 가능했다.
하지만 refreshToken 서비스는 doFilterIntenal 내부의 로직이기에 GlobalExceptionHandler로 연결 되지 못하고 예기치 못한 에러(서블릿단에서의 에러)로 연결 됐던 것
수정 후의 로직
try / catch를 이용해 서비스단에서 발생 시킨 UserException를 Filter 내부에서 직접 처리 해준다.
response를 새로 생성해 status 및 body를 생성해 내보낸다.
마지막 return을 붙이지 않으면 지정해줬던 UserException이 아닌 403 Fobidden 상태를 발생시킨다.
return으로 현재의 로직 (response를 새로 만드는 것 까지) 을 끝내지 않으면 기존의 로직 (권한을 만들어내지 못한 상태로 진행) 이 진행 되어 결국 권한이 필요했던 요청에 권한이 없는 상태로 응답을 하기 때문에 UserException 을 발생시키지 않고 403 에러 메시지가 발생 되는 것.