실행흐름 조감도📚 전체 맵실행흐름 2차
06b · 1차 프로젝트 · Thymeleaf + Session

SESSION
FLOW

1차 프로젝트 코드 실행 흐름 완전 해부 — 기동 순서·메모리·시나리오별 코드 실행 순서

Boot Memory
1차 기동 시 — 무엇이 메모리에 올라가나

BoardApplication.main()을 실행하면 아래 순서대로 JVM 메모리에 올라갑니다. 각 객체가 Heap/Stack/Method Area 중 어디에 들어가는지 함께 표시합니다.

1
JVM · Method Area
클래스 바이트코드 로딩
BoardApplication.class, UserService.class, BoardController.class 등 모든 .class 파일이 Method Area에 로딩됩니다.
메서드 코드(바이트코드), 클래스 정보, static 변수가 여기 저장.
METHOD AREA
2
Spring Container · Heap
Bean 객체 생성 — Heap에 딱 한 번
new UserRepository() → Heap에 생성
new UserService(userRepository) → Heap에 생성, userRepository 참조 주입
new BoardService(boardRepository) → Heap에 생성
new UserController(userService) → Heap에 생성
new BoardController(boardService) → Heap에 생성
new BCryptPasswordEncoder() → Heap에 생성
이 객체들은 서버가 살아있는 내내 Heap에 유지됩니다 (Singleton).
HEAP — Singleton Bean
3
JPA · Heap
Hibernate 초기화, DB 연결 풀 생성
EntityManagerFactory → Heap에 생성 (DB 연결 담당)
HikariConnectionPool → Heap에 생성 (DB 연결 풀, 기본 10개 연결 유지)
ddl-auto=update 설정이면 → DB 테이블 검증/생성
HEAP — DB 연결 풀
4
Tomcat · 별도 스레드
포트 8081 LISTEN 시작
Accept 스레드가 시작되어 8081 포트에서 HTTP 연결 대기.
ThreadPool도 초기화 (기본 최대 200 스레드).
THREAD
📌 이 시점의 Heap 상태

기동 완료 후 Heap에는:
UserRepository, UserService, BoardService, UserController, BoardController, BCryptPasswordEncoder, EntityManagerFactory, HikariConnectionPool 등이 올라가 있습니다.
아직 요청은 없으므로 Session 객체는 없고, User/Board 엔티티 객체도 없습니다.

Scenario 01
회원가입 — 코드 실행 순서 + 메모리
1
POST /user/register — 브라우저 HTML form 제출
1
Tomcat
HTTP 요청 수신 → 스레드 할당 → Stack 생성
ThreadPool에서 스레드 하나 꺼내서 이 요청 처리 담당.
그 스레드의 Call Stack이 새로 생성됩니다.
STACK — 새 스레드 스택 생성
2
DispatcherServlet → UserController
URL 매핑 → register() 메서드 호출
DispatcherServlet이 URL /user/register를 보고
UserController.register()로 연결.
Stack에 register() 프레임 push.
UserController.java
@PostMapping("/user/register")
public String register(@ModelAttribute UserDto userDto) {
    // Stack: register 프레임 생성
    // userDto → Heap에 새 UserDto 객체 생성
    userService.register(userDto); // → Service로 이동
    return "redirect:/user/login";
}
STACK — register() 프레임 HEAP — new UserDto()
3
UserService
userService.register() 호출 → Stack에 프레임 push
Controller에서 userService.register(userDto)를 호출.
Stack에 register() 프레임이 또 push됩니다.
UserService.java — register() 실행 순서
public void register(UserDto userDto) {
    // [1] Stack: register() 프레임 push

    // [2] 중복 체크 — DB SELECT 쿼리 실행
    if (userRepository.existsByUsername(userDto.getUsername()))
        throw new IllegalArgumentException(...);

    // [3] Heap에 새 User 객체 생성
    User user = new User();   // ← Heap에 생성
    user.setUsername(userDto.getUsername());

    // [4] 비밀번호 BCrypt 암호화
    // BCryptPasswordEncoder는 기동 시 이미 Heap에 있는 Bean
    String encoded = bCryptPasswordEncoder.encode(userDto.getPassword());
    // encoded → Stack의 지역변수 (String 참조, 실제 문자열은 Heap)
    user.setPassword(encoded);

    // [5] DB INSERT — @PrePersist 실행 후 INSERT 쿼리
    userRepository.save(user);
    // save() 끝나면 user 객체의 id 필드에 DB가 발급한 값이 채워짐

    // [6] register() 프레임 pop — user 지역변수 소멸
    // user 객체는 Stack 참조가 사라지면 GC 대상
}
STACK — 지역변수 user(참조), encoded(참조) HEAP — new User() 객체
4
JPA → MySQL
@PrePersist 실행 → INSERT 쿼리
userRepository.save(user)@PrePersist 실행 (createdAt 세팅) → INSERT INTO users (username, password, nickname, created_at) VALUES (?,...)
HEAP — DB 커넥션 풀에서 연결 꺼내서 사용 후 반납
5
Controller → 브라우저
redirect:/user/login 반환 → 스택 정리
return "redirect:/user/login" → HTTP 302 응답 → 브라우저가 GET /user/login 재요청.
Stack에서 모든 프레임 pop → 스레드 반환 → ThreadPool로 복귀.
STACK — 모든 프레임 pop, 스레드 반환
Scenario 02
로그인 + HttpSession — 메모리 핵심
2
POST /user/login — Session 생성 + 저장 메모리 흐름
1
UserController
login() 실행 — HttpSession 파라미터
UserController.java
@PostMapping("/user/login")
public String login(@ModelAttribute UserDto userDto,
                   HttpSession session) {
    // HttpSession: Spring이 자동으로 주입
    // 이미 세션이 있으면 기존 것, 없으면 새로 생성
    User user = userService.login(
        userDto.getUsername(), userDto.getPassword());

    session.setAttribute("loginUser", user);
    // ← 핵심! Heap의 Session 객체 안에 user 객체 참조 저장
    // JSESSIONID 쿠키가 브라우저에 전송됨

    return "redirect:/board/list";
}
2
Tomcat · Heap
HttpSession 객체 — Heap에 생성 + JSESSIONID 발급
session.setAttribute("loginUser", user)가 실행되면:

HeapHttpSession 객체가 생성됩니다.
그 안의 Map에 "loginUser" → user객체참조가 저장됩니다.
Tomcat이 랜덤 문자열 JSESSIONID를 발급해서 이 Session을 찾는 키로 사용.
브라우저에 Set-Cookie: JSESSIONID=ABC123... 응답.
HEAP — HttpSession 객체 (서버가 살아있는 한 유지)
3
이후 요청 — Session에서 유저 꺼내기
브라우저가 JSESSIONID 쿠키 자동 전송
BoardController.java — 글쓰기 요청
@PostMapping("/board/write")
public String write(@ModelAttribute BoardDto boardDto,
                   HttpSession session) {

    // [1] 브라우저가 Cookie: JSESSIONID=ABC123 전송
    // [2] Tomcat이 JSESSIONID로 Heap에서 HttpSession 객체 찾기
    // [3] 그 Session에서 loginUser 꺼내기
    User loginUser = (User) session.getAttribute("loginUser");
    // loginUser → Heap의 User 객체를 가리키는 참조
    // Stack에는 참조값(주소)만 저장, 실제 객체는 Heap

    if (loginUser == null)        // 세션 만료 또는 미로그인
        return "redirect:/user/login";

    boardService.write(boardDto, loginUser);
    return "redirect:/board/list";
}
HEAP — 기존 HttpSession에서 User 참조 꺼냄 STACK — loginUser 지역변수 (참조값만)
📌 Session의 메모리 문제 — 왜 2차에서 JWT로 바꿨나

HttpSessionHeap에 계속 남아있습니다.
기본 만료 시간은 30분. 사용자 1000명이 로그인하면 1000개의 Session 객체가 Heap에 상주.
서버가 2대로 늘어나면 서버 A의 Session을 서버 B가 모릅니다 (Session 공유 문제).

JWT는 토큰을 브라우저에 저장하고 매 요청마다 보내므로 서버는 아무것도 저장하지 않습니다 (STATELESS).

Thymeleaf
Thymeleaf 렌더링 — 서버에서 HTML 만드는 순서
1
Controller
Model에 데이터 담아서 뷰 이름 반환
BoardController.java
@GetMapping("/board/list")
public String list(Model model,
                   HttpSession session,
                   @RequestParam(defaultValue="0") int page) {

    User loginUser = (User) session.getAttribute("loginUser");
    if (loginUser == null) return "redirect:/user/login";

    Page<Board> boards = boardService.getBoardList(page);

    model.addAttribute("boards", boards);
    // Model: 뷰에 넘길 데이터 담는 Map (Heap에 존재)
    model.addAttribute("loginUser", loginUser);

    return "board/list";
    // → /templates/board/list.html 찾아서 렌더링
}
2
ThymeleafViewResolver · Heap
templates/board/list.html 읽기 → 데이터 삽입 → HTML 생성
board/list라는 뷰 이름을 받으면 → templates/board/list.html 파일 읽기 → th:each, th:text 등 Thymeleaf 표현식을 Model 데이터로 치환 → 완성된 HTML 문자열을 Heap에 생성 → HTTP 응답으로 전송.

2차/3차와 가장 큰 차이: 서버가 HTML을 만들어서 보냄. 2차/3차는 JSON을 보내고 브라우저(React)가 HTML을 만듭니다.
HEAP — 완성된 HTML 문자열 객체 (전송 후 GC)
Memory Summary
1차 — 요청 처리 중 메모리 상태 한눈에
메모리 영역항상 상주 (기동 후 유지)요청 처리 중 생성/소멸
Method Area 모든 클래스 바이트코드
UserService.class, BoardController.class 등
Heap UserService, BoardService (Bean)
UserController, BoardController (Bean)
BCryptPasswordEncoder (Bean)
EntityManagerFactory, HikariPool
HttpSession 객체들 (로그인마다 생성, 30분 유지)
new UserDto() — 요청 파싱 시
new User() — 회원가입 처리 시
new Board() — 글쓰기 처리 시
Model 객체 — 뷰 렌더링용
HTML 문자열 — 렌더링 결과
Stack 각 스레드마다 독립적 스택
메서드 호출마다 프레임 push/pop
지역변수 (참조값, 기본형) 저장
실행흐름 조감도📚 전체 맵실행흐름 2차