1차 프로젝트 코드 실행 흐름 완전 해부 — 기동 순서·메모리·시나리오별 코드 실행 순서
BoardApplication.main()을 실행하면 아래 순서대로 JVM 메모리에 올라갑니다.
각 객체가 Heap/Stack/Method Area 중 어디에 들어가는지 함께 표시합니다.
BoardApplication.class, UserService.class, BoardController.class 등
모든 .class 파일이 Method Area에 로딩됩니다.new UserRepository() → Heap에 생성new UserService(userRepository) → Heap에 생성, userRepository 참조 주입new BoardService(boardRepository) → Heap에 생성new UserController(userService) → Heap에 생성new BoardController(boardService) → Heap에 생성new BCryptPasswordEncoder() → Heap에 생성EntityManagerFactory → Heap에 생성 (DB 연결 담당)HikariConnectionPool → Heap에 생성 (DB 연결 풀, 기본 10개 연결 유지)ddl-auto=update 설정이면 → DB 테이블 검증/생성
기동 완료 후 Heap에는:
UserRepository, UserService, BoardService, UserController, BoardController, BCryptPasswordEncoder, EntityManagerFactory, HikariConnectionPool 등이 올라가 있습니다.
아직 요청은 없으므로 Session 객체는 없고, User/Board 엔티티 객체도 없습니다.
/user/register를 보고UserController.register()로 연결.register() 프레임 push.
@PostMapping("/user/register") public String register(@ModelAttribute UserDto userDto) { // Stack: register 프레임 생성 // userDto → Heap에 새 UserDto 객체 생성 userService.register(userDto); // → Service로 이동 return "redirect:/user/login"; }
userService.register(userDto)를 호출.register() 프레임이 또 push됩니다.
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 대상 }
userRepository.save(user) → @PrePersist 실행 (createdAt 세팅) →
INSERT INTO users (username, password, nickname, created_at) VALUES (?,...)
return "redirect:/user/login" → HTTP 302 응답 →
브라우저가 GET /user/login 재요청.@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"; }
session.setAttribute("loginUser", user)가 실행되면:HttpSession 객체가 생성됩니다."loginUser" → user객체참조가 저장됩니다.Set-Cookie: JSESSIONID=ABC123... 응답.
@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"; }
HttpSession은 Heap에 계속 남아있습니다.
기본 만료 시간은 30분. 사용자 1000명이 로그인하면 1000개의 Session 객체가 Heap에 상주.
서버가 2대로 늘어나면 서버 A의 Session을 서버 B가 모릅니다 (Session 공유 문제).
JWT는 토큰을 브라우저에 저장하고 매 요청마다 보내므로 서버는 아무것도 저장하지 않습니다 (STATELESS).
@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 찾아서 렌더링 }
board/list라는 뷰 이름을 받으면 → templates/board/list.html 파일 읽기 →
th:each, th:text 등 Thymeleaf 표현식을 Model 데이터로 치환 →
완성된 HTML 문자열을 Heap에 생성 → HTTP 응답으로 전송.| 메모리 영역 | 항상 상주 (기동 후 유지) | 요청 처리 중 생성/소멸 |
|---|---|---|
| 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 지역변수 (참조값, 기본형) 저장 |