톰캣 Session

박진선·2024년 7월 3일
0
post-custom-banner

톰캣의 세션 생성 과정

컨트롤러단에서 HttpServletRequest 파라미터로 선언 후 getSession(true) 메소드를 호출하면 세션이 존재하지 않을 경우 새로운 세션을 생성하는데 그 과정을 훑어보자. 우선 ReqyestFacade(org.apache.catalina.connector) -> Request(org.apache.catalina.connector)의 getSession 메소드가 호출되고 결론적으로 doGetSession 메소드 내에서 세션을 생성 또는 존재할 경우 반환하는데 doGetSession 메소드를 보면 요청 시 세션ID를 쿠키에 담아 보낸 경우 해당 세션이 톰캣 세션저장소에 저장된 세션과 일치할 경우 그 즉시 세션을 반환하고 아닐 경우 다음으로 진행된다.

ManagerBase 클래스의 createSession 메소드를 통해 비어있는 StandardSession(org.apache.catalina.session) 클래스를 생성하고 메소드를 호출해 각종 필드값을 설정한다. 그 중 generateSessionId 메소드를 통해 랜덤한 32자리 값을 생성하여 id 필드에 대입한다.

그 다음 ApplicationSessionCookieConfig.createSessionCookie 메소드를 호출 해 Cookie(jakarta.servlet.http) 클래스를 생성하는데 name은 JSESSIONID, value는 생성한 세션id 가 설정되고 HttpOnly = true, Path = /, Max-Age = -1, Partitioned = false 속성이 설정하여 쿠키가 생성된다.

response.addSessionCookieInternal 메소드를 호출해 생성한 쿠키 클래스를 바탕으로 response 헤더를 생성하여 설정하는데 Response(org.apache.catalina.connector) -> Response(org.apache.coyote) 의 addHeader 를 호출하여 헤더 이름은 Set-Cookie, 값은 JSESSIONID=7D825263CFB00C5D6012E4330B589564; Path=/; HttpOnly 같은 형태로 RFC6265 규칙에 맞게 헤더를 설정한다.
위에 쿠키클래스에 Max-Age = -1 값을 저장했지만 0보다 작을 경우 Max-Age 헤더를 생략한다.

이렇게 생성한 세션은 아파치 톰캣의 세션 저장소에 저장 된다. 톰캣의 세션 저장소는 톰캣이 점유중인 메모리 공간 내부에 있고, 그 톰캣은 결국 물리적인 서버 메모리에서 동작되므로 결국 서버 메모리에 저장된다고 보는게 맞을 것이다.

package org.apache.catalina.connector;
public class Request implements HttpServletRequest {
	protected Session doGetSession(boolean create) {
    	...
        ...
        
        if ((session != null) && !session.isValid()) {
            session = null;
        }
        if (session != null) {
            return session;
        }
        
        if (requestedSessionId != null) {
            try {
                session = manager.findSession(requestedSessionId);
            } catch (IOException e) {
                if (log.isDebugEnabled()) {
                    log.debug(sm.getString("request.session.failed", requestedSessionId, e.getMessage()), e);
                } else {
                    log.info(sm.getString("request.session.failed", requestedSessionId, e.getMessage()));
                }
                session = null;
            }
            if ((session != null) && !session.isValid()) {
                session = null;
            }
            if (session != null) {
                session.access();
                return session;
            }
        }
        
        String sessionId = getRequestedSessionId();
        
        ...
        ...
        
        session = manager.createSession(sessionId);

        // Creating a new session cookie based on that session
        if (session != null && trackModesIncludesCookie) {
            Cookie cookie =
                    ApplicationSessionCookieConfig.createSessionCookie(context, session.getIdInternal(), isSecure());

            response.addSessionCookieInternal(cookie);
        }

        if (session == null) {
            return null;
        }

        session.access();
        return session;
    
    }
}

public abstract class ManagerBase extends LifecycleMBeanBase implements Manager {
	public Session createSession(String sessionId) {
	...
    ...
    
	Session session = createEmptySession();

	// Initialize the properties of the new session and return it
	session.setNew(true);
    session.setValid(true);
    session.setCreationTime(System.currentTimeMillis());
    session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
    String id = sessionId;
    if (id == null) {
    	id = generateSessionId();
    }
    session.setId(id);
    sessionCounter++;

	...
    ...
    
    return session;

	}
}

package org.apache.coyote;
public final class Response {
	...
    ...
	final MimeHeaders headers = new MimeHeaders();
    
    public void addHeader(String name, String value, Charset charset) {
        char cc = name.charAt(0);
        if (cc == 'C' || cc == 'c') {
            if (checkSpecialHeader(name, value)) {
                return;
            }
        }
        MessageBytes mb = headers.addValue(name);
        if (charset != null) {
            mb.setCharset(charset);
        }
        mb.setString(value);
    }
}
profile
주니어 개발자 입니다
post-custom-banner

0개의 댓글