현재 F-Lab 멘토링에서 프로젝트 진행 중 세션 불일치에 대한 문제점을 해결하기 위해 멘토님께서 "HttpSession
을 이해하셨을까요?"라는 질문을 하셨다.
그래서 나는 "이 정도면 이해된 것이 아닐까?"라고 가볍게 생각했다.
하지만 멘토님께서 "왜 코드 한줄로 세션이 생성되고 쿠키에 add가 되는 지", "내부 로직은 어떻게 짜여져있길래 이렇게 사용할 수 있지?" 라는 의문을 가지고 코드를 끝까지 찾아내야 하며,
어떻게 동작하는 지 알고 있어야 HttpSession
을 이해했다고 말할 수 있다고 하셨다.
멘토링이 끝나고 이때까지 내가 접근한 방식이 달랐다고 생각이 들었고,
멘토님께 보여드렸던 모습들이 부끄러웠다.
우선 프로젝트 진행 중 발생한 문제점들은 이렇다.
1. 랜덤으로 발생하는 세션 ID를 커스텀 쿠키로 만들려고 했던 것
2. 쿠키에 세션 ID가 두번 생성이 되는 문제점이다.
프로젝트 진행 중 발생한 문제점들을 가지고 다시 HttpSession
에 대해 자세하게 살펴보자는 마음으로 다시 접근했다.
HttpSession은 자바 서블릿 API에 의해 제공된다.
톰캣 내부 구현에 있으며 인터페이스로 세션 식별자, 생성 시간, 마지막으로 엑세스한 시간 등 세션에 대한 정보를 보거나 조작하게 해준다.
HttpSession 코드와 구현체를 확인해보자
HttpSession
우선 코드는 세션 아이디를 조회하거나, 생성 시간을 조회하는 등의 메서드가 있고 구현체로는 StandardSession
과 StandardSessionFacade
가 있다.
StandardSession
StandardSession
을 살펴보면HttpSession
,Session
,Serializable
을 구현하고 있고
public StandardSession(Manager manager)
생성자를 보면Manager
를 매개변수로 받은 것을 볼 수 있다.
StandardSessionFacade
StandardSessionFacade
를 보면HttpSession
인터페이스와 똑같은 메서드를 볼 수 있다.
StandardSessionFacade
는 위에서 살펴본StandardSession
클래스의 복잡한 내부를 감추고HttpSession
인터페이스를 구현하면서StandardSession
과 같은 세션 구현을 변경하더라도StandardSessionFacade
클래스와HttpSession
인터페이스는 변경하지 않고 호환성을 유지할 수 있게 해준다.
정리를 해보자면
StandardSession
생성자에서 Manager
를 매개변수로 받은 것을 찾았는데 Manager
인터페이스를 살펴보자.Manager
Manager
인터페이스를 보면 createSession(String var1)
메서드를 볼 수 있는데 구현한 곳을 따라가보자.
ManagerBase
해당 메서드가 구현된 로직을 보면 sessionId
가 Null
일때 generateSessionId()
메서드가 실행되는데
ManagerBase
sessionIdGenerator
의 generateSessionId()
메서드를 반환하는 것을 찾아볼 수 있다.
그러면 또 SessionIdGenerator
를 따라가보자.
SessionIdGenerator
SessionIdGenerator
에서 generateSessionId(String var1)
메서드를 구현한 것을 또 찾아가보자.
StandardSessionIdGenerator
StandardSessionIdGenerator
클래스에서 16바이트의 랜덤 데이터를 생성해 세션 식별자 즉, Session Id를 생성하는 로직을 찾았다.
앞에서 Session Id
가 어떻게 생성되는 지 로직을 파헤쳐보았는데 여전히 궁금증은 풀리지 않았다.
JSESSIONID
라는 쿠키에 어떻게 자동으로 생성된 세션ID가 add 되는 것일까?
HttpSession
객체를 사용하려면 HttpServletRequest
의 getSession()
메서드를 사용할 것이다.
바로 파헤쳐 보자.
HttpServletRequest
HttpServletRequest
를 구현하는 클래스 중 Request
라는 클래스를 살펴보자.
Request
doGetSession(create)
메서드를 확인해보자.
Request.doGetSession()
doGetSession()
메서드 로직을 내리다 보면 ApplicationSessionCookieConfig.createSessionCookie()
메서드로 쿠키 객체를 생성하고
해당 쿠키를 response.addSessionCookieInternal(cookie);
메서드를 통해 HttpServletResponse
의 구현체인 Response
에다가 쿠키를 추가해준다.
먼저 ApplicationSessionCookieConfig
의 createSessionCookie()
메서드를 확인해보자.
ApplicationSessionCookieConfig.createSessionCookie()
여기서 쿠키가 SessionConfig
의 getSessionCookieName
하고 sessionId
로 생성되고 return 해주는 것을 볼수가 있다.
SessionConfig
SessionConfig
에서 JSESSIONID
을 찾을 수 있었다.
그 다음 response.addSessionCookieInternal(cookie);
의 addSessionCookieInternal()
메서드를 보면
Response.addSessionCookieInternal()
응답헤더에 쿠키를 추가해주는 것을 볼 수 있다.
request.getSession()
코드 한줄로 내부에선 Session Id
가 어떻게 생성되고
쿠키에 JSESSIONID
가 어떻게 추가되는 지 찾아보니 HttpSession
이 어떻게 동작하는지 자세하게 알 수 있었다.
HttpSession
을 시작으로 연결되는 코드들을 하나하나 읽으면서 어떻게 동작하는 지 찾아봤고 코드를 살펴보면서 멘토님이 말씀하신 의도를 알수 있었다.
추가로 StandardSessionFacade라는 래퍼(Wrapper)를 통해 제공하는 것도, Facade 패턴을 사용해서 내부 구현체에 직접 접근하지 못하도록 구현한 것도 알게되었다.
"그냥 되네?" 하고 넘기는 습관보다 항상 "왜?" 라는 이유를 가지고 하나하나 파보고 찾아보고 하는 습관을 지금 잡고 가는 것이 매우 중요하다고 말씀하셨다.
다시 생각해보니 좋은 코드를 짜는 것도 중요하지만 해당 기능들이 어떻게 동작하는 지, 구현은 어떻게 되어있는 지 찾아보고 그 기능을 잘 알고 사용하는 것도 잘하는 개발자가 되는 길이지 않을까?
오늘의 교훈
원리를 알아야 문제를 해결할 수 있고, 실무에 적용할 수 있으며, 흥미를 가질 수 있다.