이번 포스팅에서는 HttpSession과 @SessionAttribute에 대해 기록한다.
세션에서 막힌지 며칠 된 것 같은데 세션이 왜 이렇게 이해가 힘들었는지 모르겠다.
머릿 속에서 내부적으로 동작 흐름이 납득이 안 됐는지,
이해를 했다고 생각해도 사용하려고 하면 외워서 쓰는 것 같은 기분에 영 찝찝했다.
그래도 오늘은 자세히 알아보면서 좀 체득이 된 것 같아서 이에 대한 내용을 정리해보려 한다.
HttpSession은 웹 서버가 사용자 요청을 추적하고 사용자 간의 상태 정보를 유지하기 위해 사용하는 Java 인터페이스이다. HTTP 프로토콜의 stateless 특성을 보완하기 위해 사용되며, 서버 측에 사용자 데이터를 임시로 저장하고 클라이언트에게는 세션 ID를 쿠키(JSESSIONID)로 전달하여 사용자를 식별한다.
코드에서의 HttpSession session은 현재 요청이 가지고 온 JSESSIONID로 식별되는 단 하나의 세션 객체이다. 세션 저장소 안의 한 칸을 가리킨다고 보면 된다.
예를 들어, 세션 저장소에 다음과 같이 저장되어 있다고 해보자.
🌱 세션 저장소
├─ JSESSIONID = A01 → { loginMember : UserA }
├─ JSESSIONID = B02 → { loginMember : UserB }
└─ JSESSIONID = C03 → { loginMember : UserC }
그리고 클라이언트 요청으로 Cookie: JSESSIONID=A01 라고 왔다고 치면
이 때, 컨트롤러 파라미터인 HttpSession session은 JSESSIONID=A01을 보고 A01 세션 객체를 찾아서 넣어준다.
또 다른 컨트롤러 파라미터인 @SessionAttribute("loginMember")는 그 세션 객체 내부에서 "loginMember" 키로 값을 꺼내서 주입한다.
🌱 예시
@SessionAttribute("loginMember") SessionMember sessionMember
-> UserA
즉, @SessionAttribute는 해당 사용자 전체 세션 객체 내에서 "loginMember"라는 세션 attribute만 꺼내고 HttpSession은 해당 사용자 전체 세션 객체 자체를 주입한다.
따라서 흐름으로 보면
HttpSession은 이미 서버 메모리에 존재하고, 스프링이 그 HttpSession 전체를 파라미터로 넣어준다면,@SessionAttribute는 그 HttpSession 안에서 특정 attribute만 꺼낸다.
이렇게 볼 수 있겠다.
@SessionAttribute(name = "loginMember")하면 key가 "loginMember"인 값만 가져오는 거라고 했는데, 그럼 여러 값을 넣을 수 있을까? 하면 답은 "그렇다"이다.
HttpSession은 Map<String, Object> 구조이고, 여러 값을 넣을 수 있게 설계된 이유는 원래 세션은 원래 로그인만을 위한 것이 아니였기 때문이다.
이렇게 서버 측에서 유지해야 하는 사용자 상태(user state)를 저장하는 것 또한 세션의 역할이였지만,
현재 시점에서는 서버 부담 증가, 확장성 문제 등으로 세션을 거의 로그인 용도로만 사용한다.
또 Local Storage, Redis, JWT, 쿠키 기반 간단 데이터 등으로 대부분 대체 가능해졌다.
HttpSession은 세션 객체 전체, @SessionAttribute는 세션 객체 안에서 특정 key의 값만 꺼내오는 것