CORS는 무엇인가요?

브라우저에서는 보안적인 이유로 cross-origin HTTP 요청들을 제한합니다. 그래서 cross-origin 요청을 하려면 서버의 동의가 필요합니다. 만약 서버가 동의한다면 브라우저에서는 요청을 허락하고, 동의하지 않는다면 브라우저에서 거절합니다.

이러한 허락을 구하고 거절하는 메커니즘을 HTTP-header를 이용해서 가능한데, 이를 CORS(Cross-Origin Resource Sharing)라고 부릅니다. 그래서 브라우저에서 cross-origin 요청을 안전하게 할 수 있도록 하는 메커니즘입니다.

 

cross-origin

cross-origin이란 다음 중 한 가지라도 다른 경우를 말합니다.

  1. 프로토콜 - http와 https는 프로토콜이 다르다.
  2. 도메인 - domain.com과 other-domain.com은 다르다.
  3. 포트 번호 - 8080포트와 3000포트는 다르다.

 

출처(Origin)가 무엇인가요?

서버의 위치를 의미하는 https://google.com과 같은 URL들은 마치 하나의 문자열 같아 보여도, 사실은 여러 개의 구성 요소로 이루어져있다.

 

이때 출처는 Protocol과 Host, 그리고 위 그림에는 나와있지 않지만 :80, :443과 같은 포트 번호까지 모두 합친 것을 의미한다. 즉, 서버의 위치를 찾아가기 위해 필요한 가장 기본적인 것들을 합쳐놓은 것이다.

또한 출처 내의 포트 번호는 생략이 가능한데, 이는 각 웹에서 사용하는 HTTP, HTTPS 프로토콜의 기본 포트 번호가 정해져있기 때문이다. 

 

그러나 만약 https://google.com:443과 같이 출처에 포트 번호가 명시적으로 포함되어 있다면 이 포트 번호까지 모두 일치해야 같은 출처라고 인정된다. 하지만 이 케이스에 대한 명확한 정의가 표준으로 정해진 것은 아니기 때문에, 더 정확히 이야기하자면 어떤 경우에는 같은 출처, 또 어떤 경우에는 다른 출처로 판단될 수도 있다. 

 

CORS는 왜 필요한가요?

CORS가 없이 모든 곳에서 데이터를 요청할 수 있게 되면, 다른 사이트에서 원래 사이트를 흉내낼 수 있게 됩니다. 예를 들어서 기존 사이트와 완전히 동일하게 동작하도록 하여 사용자가 로그인을 하도록 만들고, 로그인했던 세션을 탈취하여 악의적으로 정보를 추출하거나 다른 사람의 정보를 입력하는 등 공격을 할 수 있습니다. 이러한 공격을 할 수 없도록 브라우저에서 보호하고, 필요한 경우 에만 서버와 협의하여 요청할 수 있도록 하기 위해서 필요합니다.

 

CORS는 어떻게 동작하나요?

Simple requests인 경우

  1. 서버로 요청을 합니다.
  2. 서버의 응답이 왔을 때 브라우저가 요청한 Origin과 응답한 헤더 Access-Control-Request-Headers의 값을 비교하여 유효한 요청이라면 리소스를 응답합니다. 만약 유효하지 않은 요청이라면 브라우저에서 이를 막고 에러가 발생합니다.

Simple requests란?

HTTP method가 다음 중 하나이면서

  • GET
  • HEAD
  • POST

자동으로 설정되는 헤더는 제외하고, 설정할 수 있는 다음 헤더들만 변경하면서

  • Accept
  • Accept-Language
  • Content-Language

Content-Type이 다음과 같은 경우

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Simple requqets라고 부릅니다. 이 요청은 추가적으로 확인하지 않고 바로 본 요청을 보냅니다.

 

preflight 요청일 경우

  1. Origin헤더에 현재 요청하는 origin과, Access-Control-Request-Method헤더에 요청하는 HTTP method와 Access-Control-Request-Headers요청 시 사용할 헤더를 OPTIONS 메서드로 서버로 요청합니다. 이때 내용물은 없이 헤더만 전송합니다.
  2. 브라우저가 서버에서 응답한 헤더를 보고 유효한 요청인지 확인합니다. 만약 유효하지 않은 요청이라면 요청은 중단되고 에러가 발생합니다. 만약 유효한 요청이라면 원래 요청으로 보내려던 요청을 다시 요청하여 리소스를 응답받습니다.

preflight 요청이란?

Simple requests가 아닌 cross-origin요청은 모두 preflight 요청을 하게 되는데, 실제 요청을 보내는 것이 안전한지 확인하기 위해 먼저 OPTIONS 메서드를 사용하여 cross-origin HTTP 요청을 보냅니다. 이렇게 하는 이유는 사용자 데이터에 영향을 미칠 수 있는 요청이므로 사전에 확인 후 본 요청을 보냅니다.

 

요청 헤더 목록

  • Origin
  • Access-Control-Request-Method
    • preflight 요청을 할 때 실제 요청에서 어떤 메서드를 사용할 것인지 서버에게 알리기 위해 사용됩니다.
  • Access-Control-Request-Headers
    • preflight요청을 할 때 실제 요청에서 어떤 header를 사용할 것인지 서버에게 알리기 위해 사용됩니다.

 

응답 헤더 목록

  • Access-Control-Allow-Origin
    • 브라우저가 해당 origin이 자원에 접근할 수 있도록 허용합니다. 혹은 *은 credentials이 없는 요청에 한해서 모든 origin에서 접근이 가능하도록 허용합니다.
  • Access-Control-Expose-Headers
    • 브라우저가 액세스할 수 있는 서버 화이트리스트 헤더를 허용합니다.
  • Access-Control-Max-Age
    • 얼마나 오랫동안 preflight요청이 캐싱 될 수 있는지를 나타낸다.
  • Access-Control-Allow-Credentials
    • Credentials가 true 일 때 요청에 대한 응답이 노출될 수 있는지를 나타냅니다.
    • preflight 요청에 대한 응답의 일부로 사용되는 경우 실제 자격 증명을 사용하여 실제 요청을 수행할 수 있는지를 나타냅니다.
    • 간단한 GET 요청은 preflight되지 않으므로 자격 증명이 있는 리소스를 요청하면 헤더가 리소스와 함께 반환되지 않으면 브라우저에서 응답을 무시하고 웹 콘텐츠로 반환하지 않습니다.
  • Access-Control-Allow-Methods
    • preflight 요청에 대한 대한 응답으로 허용되는 메서드들을 나타냅니다.
  • Access-Control-Allow-Headers
    • preflight 요청에 대한 대한 응답으로 실제 요청 시 사용할 수 있는 HTTP 헤더를 나타냅니다.

[참고자료]

https://hannut91.github.io/blogs/infra/cors

 

CORS란 무엇인가? – Yunseok's Dev Blog

 

hannut91.github.io

 

https://evan-moon.github.io/2020/05/21/about-cors/

 

CORS는 왜 이렇게 우리를 힘들게 하는걸까?

이번 포스팅에서는 웹 개발자라면 한번쯤은 얻어맞아 봤을 법한 정책에 대한 이야기를 해보려고 한다. 사실 웹 개발을 하다보면 CORS 정책 위반으로 인해 에러가 발생하는 상황은 굉장히 흔해서

evan-moon.github.io

 

'Coding > Spring' 카테고리의 다른 글

[33] 실전 프로젝트 기술 개념이해(1) WebSocket/WebRTC  (0) 2022.12.31
[32] 이번주에 궁금했던 부분 정리  (0) 2022.12.30
[30] Spring 심화주차 키워드정리  (0) 2022.12.18
[28] Transaction  (0) 2022.12.14
[27] Spring AOP  (0) 2022.12.14

 

  • 그럼 아래와 같은 gitignore 파일이 생성된다. 복사해서 본인의 gitignore에 추가하면 끝 ! 

 

  • 아래는 이번 프로젝트때 내가 사용한 gitignore 파일 이다 : ) 
application-local.properties

# intelliJ
HELP.md
.gradle
.idea
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf

# AWS User-specific
.idea/**/aws.xml

# Generated files
.idea/**/contentModel.xml

# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml

# Gradle
.idea/**/gradle.xml
.idea/**/libraries

# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn.  Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr

# CMake
cmake-build-*/

# Mongo Explorer plugin
.idea/**/mongoSettings.xml

# File-based project format
*.iws

# IntelliJ
out/

# mpeltonen/sbt-idea plugin
.idea_modules/

# JIRA plugin
atlassian-ide-plugin.xml

# Cursive Clojure plugin
.idea/replstate.xml

# SonarLint plugin
.idea/sonarlint/

# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

# Editor-based Rest Client
.idea/httpRequests

# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721

# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr

# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/

# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml

# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/

# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$

# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml

# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### macOS Patch ###
# iCloud generated files
*.icloud

### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

 

 

 


https://www.toptal.com/developers/gitignore

 

gitignore.io

Create useful .gitignore files for your project

www.toptal.com

https://niceman.tistory.com/114

 

Git - 캐시(Cache) 삭제 방법 및 상세 설명

Git - Cache 삭제 설명 Git을 사용한 프로젝트 진행 중에 크리티컬한 문제는 아니지만, 신경쓰이는 두 가지 상황이 발생했습니다. 첫 번째 경우는 프로젝트와 관련 없는 private 종류의 폴더를 원격 저

niceman.tistory.com

 

🔐 스프링 시큐리티를 사용해 회원관리하는 방법을 순서도를 통해 정리해 보세요. 

<회원 가입>

 

1. Client -> Server : 회원가입에 필요한 정보 (username, password, email 등)

2. Server (회원가입 처리)

  • 중복 회원 ID 확인
  • 패스워드 암호화
  • 회원 역할 설정 (USER, ADMIN)

3. Server -> DB : 회원정보 DB 에 저장

 

 

< 로그인 >

 

  1. Client → Server : 로그인에 필요한 정보 (username, password)
  2. Server (로그인 처리)
    • 회원 DB 에서 username 을 가진 회원정보 가져옴 (회원 정보가 없으면 에러 발생)
    • 회원 DB 의 username, password 와 Client 에서 전달받은 username, password 가 동일한지 비교
  3. Server → Session : 로그인 성공 시 Session 에 저장
  4. Server → Client : Session 쿠키 전달 (JSESSIONID)
  5. Client : Session 쿠키 저장

 

< 로그인 이후 로그인 상태 유지 방법 >

 

 

  • Client 에서 Server 에 API 요청할때마다 Session 쿠키를 전달

 

🔐 단위 테스트 코드 작성 시 장/단점을 정리해 보세요.

< 단위 테스트란? >

  • 프로그램을 작은 단위로 쪼개서 각 단위가 정확하게 동작하는지 검사하고 이를 통해 문제 발생 시 정확하게 어느 부분이 잘못되었는지를 재빨리 확인할 수 있게 해준다.  
    1. 장점
      • 예상 동작과 실제 동작을 비교하여 빠르고 정확한 테스트가 가능하기 때문에 초기 개발의 디버깅이 쉬워집니다.
      • 어플리케이션이 변경(기능 확장 또는 리팩터링 등)되더라도 올바르게 작동하는 지 확인할 수 있습니다.
      • 단위 테스트 자체를 어플리케이션에 대한 문서로 사용할 수 있다. 특히 잘 만든 테스트 케이스는 API 기능을 쉽게 파악할 수 있도록 도와줍니다.
      • 여러 빌드 도구들(maven, gradle 등)은 테스트 자동화 기능을 포함하고 있습니다.
    2. 단점
      • 테스트 코드까지 작성해야하기 때문에 개발 시간이 오래 걸리게 됩니다.
      • 어플리케이션 변경 사항을 테스트 코드에도 적용해야 하기 때문에 테스트 코드를 유지보수하는 비용이 든다.

 

🔐 AOP(Aspect Oriented Programming)란 무엇인가?

  • AOP는 스프링의 가장 중요한 세 가지 특징인 IoC(제어의 역전), DI(의존성 삽입), AOP(관점 지향 프로그래밍)중 하나. 관점 지향 프로그래밍은 흩어진 Aspect를 모듈화 할 수 있는 프로그래밍 기법.
  • 관점 지향은 어떤 로직을 기준으로 핵심적인 관점, 부가적인 관점으로 나누어 본다는 말이고 따라서 관점을 기준으로 각각 모듈화하는 프로그래밍 기법
    • 핵심기능 : 각 API 별 수행해야 할 비즈니스 로직  ex) 상품 키워드 검색, 관심상품 등록, 회원 가입, 관심상품에 폴더 추가 등 ....
    • 부가기능 : 핵심기능을 보조하는 기능 ex) 데이터베이스 연결, 파일 입출력, 회원 패턴 분석을 위한 로그 기록, API 수행시간 저장 등
    • 모듈화 : 어떤 공통된 로직이나 기능을 하나의 단위로 묶는 것
  • AOP는 OOP를 대신하는 새로운 개념이 아니라, 기존 OOP를 더욱 보완, 확장하여 OOP를 OOP답게 사용할 수 있도록 도와주는 개념 (OOP(Object-oriented Programming란 객체 지향 프로그래밍)과 나란히 하는, 서로 보완관계에 있는 기술)

 

🔐 @Transactional이란 무엇인가?

  • 여러 작업을 진행하다가 문제가 생겼을 경우 이전 상태로 롤백하기 위해 사용되는 것이 트랜잭션(Transaction) 이다.
  • 트랜잭션은 더 이상 쪼갤 수 없는 최소 작업 단위를 의미한다. 그래서 트랜잭션은 commit으로 성공 하거나 rollback으로 실패 이후 취소되어야 한다. 하지만 모든 트랜잭션이 동일한 것은 아니고 속성에 따라 동작 방식을 다르게 해줄 수 있다.
  • 위에서 설명한 것과 마찬가지로 트랜잭션의 마무리 작업으로는 크게 2가지가 있다.
    • 트랜잭션 커밋: 작업이 마무리 됨
    • 트랜잭션 롤백: 작업을 취소하고 이전의 상태로 돌림
  • 만약 여러 작업이 모두 마무리 되었다면 트랜잭션 커밋을 통해 작업이 마무리되었음을 알려주어 반영해야 하며, 만약 문제가 생겼다면 작업 취소를 위해 트랜잭션 롤백 처리를 해주어야 한다.

 

🔐 WAS란 무엇인가? Web Server와 차이점은 무엇인가?

 

 

Web Server

  • 하드웨어 : Web 서버가 설치되어 있는 컴퓨터
  • 소프트웨어 : 웹 브라우저 클라이언트로부터 HTTP 요청을 받아 정적인 컨텐츠(.html .jpeg .css 등)를 제공하는 컴퓨터 프로그
  • Web Server의 기능 : HTTP 프로토콜을 기반으로 하여 클라이언트(웹 브라우저 또는 웹 크롤러)의 요청을 서비스 하는 기능을 담당한다. 요청에 따라 아래의 두 가지 기능 중 적절하게 선택하여 수행한다.
    • 정적인 컨텐츠 제공 : WAS를 거치지 않고 바로 자원을 제공한다.
    • 동적인 컨텐츠 제공을 위한 요청 전달 : 클라이언트의 요청(Request)을 WAS에 보내고, WAS가 처리한 결과를 클라이언트에게 전달(응답, Response)한다. 클라이언트는 일반적으로 웹 브라우저를 의미한다. Web Server의 예 Ex) Apache Server, Nginx, IIS(Windows 전용 Web 서버) 등

 

WAS

WAS의 개념

  • DB 조회나 다양한 로직 처리를 요구하는 동적인 컨텐츠를 제공하기 위해 만들어진 Application Server HTTP를 통해 컴퓨터나 장치에 애플리케이션을 수행해주는 미들웨어(소프트웨어 엔진)이다.
  • “웹 컨테이너(Web Container)” 혹은 “서블릿 컨테이너(Servlet Container)”라고도 불린다.
  • Container란 JSP, Servlet을 실행시킬 수 있는 소프트웨어를 말한다. 즉, WAS는 JSP, Servlet 구동 환경을 제공한다.

 

WAS의 역할

  • WAS = Web Server + Web Container Web Server 기능들을 구조적으로 분리하여 처리하고자하는 목적으로 제시되었다.
  • 분산 트랜잭션, 보안, 메시징, 쓰레드 처리 등의 기능을 처리하는 분산 환경에서 사용된다.
  • 주로 DB 서버와 같이 수행된다.
  • 현재는 WAS가 가지고 있는 Web Server도 정적인 컨텐츠를 처리하는 데 있어서 성능상 큰 차이가 없다.

 

WAS의 주요 기능

  • 프로그램 실행 환경과 DB 접속 기능 제공
  • 여러 개의 트랜잭션(논리적인 작업 단위) 관리 기능
  • 업무를 처리하는 비즈니스 로직 수행
  • WAS의 예 Ex) Tomcat, JBoss, Jeus, Web Sphere 등

Q1. JPA 연관관계 매핑

  • JPA에서 객체와 관계형 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는 것은 매우 중요! JPA의 목적인 객체 지향 프로그래밍과 데이터베이스 사이의 패러다임 불일치를 해결이라는 것과 가장 직접적으로 연관되어 있기 때문.
  • 연관 관계 매핑은 비즈니스 로직, 비즈니스 요구사항에 따라 개발자가 적절한 관계 설정 방법을 선택해야 함
  • 연관 관계 매핑시 고려사항
    • 1.방향 : 단방향, 양방향 (객체 참조)
    • 2.연관 관계의 주인 : 양방향일 때, 연관 관계에서 관리 주체
    • 3.다중성 : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)

 

 Q2. 순환참조 정의/이유/해결방법

 

<순환참조 정의>

  • 서로 다른 두 개의 클래스가 서로 참조하고 있는 상태를 말한다.
  • JPA 순환 참조는 1:N , N:1, 양방향 관계에서 일어날 수 있다.

 

<순환참조 이유>

  • 스프링에서 DI를 통해 생성자 주입을 할 경우 순환 참조 문제가 발생할 수 있다.
  • 생성자 주입은 객체를 생성할 때 주입되기 때문에 객체가 반드시 존재해야 한다.
  • A가 B에 의존하고 B가 C에 의존한다면
  • A -> B -> C
  • 스프링 컨테이너는 C -B - A 순으로 객체를 생성하게 됩니다.
  • 그러나 A가 B에 의존하고 B가 A에 의존적이라면 어떠한 객체를 먼저 만들어야 하는지 문제가 생깁니다.

 

<해결 방법>

@jsonignore (지양함)

  • 간단하게 순환참조를 해결할 수 있지만, 연관관계 복잡하게 얽혀있으면 문제가 많음 (사용해야할 떄, 사용하지 못하기도 함)
  • 어노테이션이 붙은 객체를 Json 직렬화를 하지 않음

DTO (지향)

  • 무한 순환 참조는 객체를 JSON 형태로 변환하는 직렬화 과정에서 발생
  • JSON으로 직렬화 할 객체에 연관 관계의 필드를 넣지 않음으로 문제 해결 가능
  • 즉, DTO에, 필요한 필드만 만들어서 담아, 순환참조가 일어나지 않도록 하자

 

 Q3. Exception 예외처리를 따로 다루는 이유?

  1. 웹 어플리케이션에서의 에러를 프론트엔드와 백엔드 모두가 잘 알지 못하면, 서비스하는 환경에서 발생하는 에러에 대해서 제대로 대응 할 수 없습니다.
  2. 에러를 처리하는 것 역시 관심사를 분리해서 더 효율적으로 처리 할 수 있지 않을까 고민해보는 시간이 필요해서 입니다.

 

 Q4. Spring Security 동작 원리

일반적인 Form Login 절차

 

 1. 요청 수신

  • 사용자가 form을 통해 로그인 정보가 담긴 Request를 보낸다.

2. 토큰 생성

  • AuthenticationFilter가 요청을 받아서 UsernamePasswordAuthenticationToken토큰(인증용 객체)을 생성
  • UsernamePasswordAuthenticationToken은 해당 요청을 처리할 수 있는 Provider을 찾는데 사용

3. AuthenticationFilter로 부터 인증용 객체를 전달 받는다.

  • Authentication Manager에게 처리 위임
  • Authentication Manager는 List형태로 Provider들을 갖고 있다.

4. Token을 처리할 수 있는 Authentication Provider 선택

  • 실제 인증을 할 AuthenticationProvider에게 인증용 객체를 다시 전달한다.

5. 인증 절차

  • 인증 절차가 시작되면 AuthenticationProvider 인터페이스가 실행되고 DB에 있는 사용자의 정보와 화면에서 입력한 로그인 정보를 비교

6. UserDetailsService의 loadUserByUsername메소드 수행

  • AuthenticationProvider 인터페이스에서는 authenticate() 메소드를 오버라이딩 하게 되는데 이 메소드의 파라미터인 인증용 객체로 화면에서 입력한 로그인 정보를 가져올 수 있다.

7. AuthenticationProvider 인터페이스에서 DB에 있는 사용자의 정보를 가져오려면, UserDetailsService 인터페이스를 사용한다.

 

8. UserDetailsService 인터페이스는 화면에서 입력한 사용자의 username으로 loadUserByUsername() 메소드를 호출하여 DB에 있는 사용자의 정보를 UserDetails 형으로 가져온다. 만약 사용자가 존재하지 않으면 예외를 던진다. 이렇게 DB에서 가져온 이용자의 정보와 화면에서 입력한 로그인 정보를 비교하게 되고, 일치하면 Authentication 참조를 리턴하고, 일치 하지 않으면 예외를 던진다.

 

9. 인증이 완료되면 사용자 정보를 가진 Authentication 객체를 SecurityContextHolder에 담은 이후 AuthenticationSuccessHandle를 실행한다.(실패시 AuthenticationFailureHandler를 실행한다.)

 

 Q5. TDD란?

 

TDD란? Test-Driven Development의 약자

  • 테스트 코드를 먼저 작성하고 실제 동작하는 코드를 개발하는 순서로 개발하는 개발 방법론
  • 설계 → 개발 → 테스트에서
  • 설계 → 테스트 → 개발 순서로 하는 것을 말함

 

 Q6. 싱글톤 사용 이유

  • 변경되면 안되는 사항 예를 들면 암호화된 비밀번호, 같은 객체가 변하면 안되기 때문에 선언해야한다. 
  • 스프링 구조 자체가, 스프링 컨테이너에 내부 빈으로 등록하다는 것 자체가 싱글톤으로 등록 된다는 것.
  • -> 스프링 컨테이너, 빈을 공부하자

'Coding > Spring' 카테고리의 다른 글

[32] 이번주에 궁금했던 부분 정리  (0) 2022.12.30
[31] CORS  (0) 2022.12.18
[28] Transaction  (0) 2022.12.14
[27] Spring AOP  (0) 2022.12.14
[26] OAuth / 소셜 로그인  (0) 2022.12.14

1. Transaction(트랜잭션)

 

트랜잭션(Transaction)의 필요성 

  • 여러 작업을 진행하다가 문제가 생겼을 경우 이전 상태로 롤백하기 위해 사용되는 것이 트랜잭션(Transaction) 이다.
  • 트랜잭션은 더 이상 쪼갤 수 없는 최소 작업 단위를 의미한다. 그래서 트랜잭션은 commit으로 성공 하거나 rollback으로 실패 이후 취소되어야 한다. 하지만 모든 트랜잭션이 동일한 것은 아니고 속성에 따라 동작 방식을 다르게 해줄 수 있다. 
  • 위에서 설명한 것과 마찬가지로 트랜잭션의 마무리 작업으로는 크게 2가지가 있다.
    • 트랜잭션 커밋: 작업이 마무리 됨
    • 트랜잭션 롤백: 작업을 취소하고 이전의 상태로 돌림
  • 만약 여러 작업이 모두 마무리 되었다면 트랜잭션 커밋을 통해 작업이 마무리되었음을 알려주어 반영해야 하며, 만약 문제가 생겼다면 작업 취소를 위해 트랜잭션 롤백 처리를 해주어야 한다.

 

② Transaction의 기본 방법 

Transaction은 2개 이상의 쿼리를 하나의 커넥션으로 묶어 DB에 전송하고, 이 과정에서 에러가 발생할 경우 자동으로 모든 과정을 원래대로 되돌려 놓는다. 이러한 과정을 구현하기 위해 Transaction은 하나 이상의 쿼리를 처리할 때 동일한 Connection 객체를 공유하도록 한다.

 

 

 

2. Spring에서 Transaction의 사용법

① Spring의 Transaction 

Spring은 코드 기반의 트랜잭션(Programmatic Transaction) 처리 뿐만 아니라 선언적 트랜잭션(Declarative Transaction)을 지원하고 있다. Spring이 제공하는 트랜잭션 템플릿 클래스를 이용하거나  설정파일, 어노테이션을 이용해서 트랜잭션의 범위 및 규칙을 정의할 수 있다. Spring에서는 주로 선언적 트랜잭션을 이용하는데, <tx:advice>태그 또는 @Transactional 어노테이션을 이용하는데, 쿼리문을 처리하는 과정에서 에러가 났을 경우 자동으로 Rollback 처리를 해준다.

 

② Spring @Transactional 

일반적으로 Spring에서는 Service Layer에서 @Transactional 을 추가하여 Transaction 처리를 한다. 아래의 예시는 상점과 관련된 Service 부분이고, 데이터의 조회만 일어나는 select 메소드에서는 @Transactional 을 활용하고 있지 않지만, 값을 추가하거나 변경 또는 삭제하는 insert, update, delete 메소드에는 @Transactional을 추가하여 트랜잭션을 설정해두었다.

 

package com.mang.store.service;

import com.mang.store.vo.StoreVO;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface StoreService {

    List<StoreVO> selectStoreInfoList(StoreVO storeVO);

    StoreVO selectStoreInfo(StoreVO storeVO);

    @Transactional
    int insertStoreInfo(StoreVO storeVO);

    @Transactional
    int updateStoreInfo(StoreVO storeVO);

    @Transactional
    int deleteStoreInfo(StoreVO storeVO);

}

 

③ 비지니스 로직과의 결합

트랜잭션을 중구난방으로 적용하는 것은 좋지 않다. 대신 특정 계층의 경계를 트랜잭션 경계와 일치시키는 것이 좋은데, 일반적으로 비지니스 로직을 담고 있는 서비스 계층의 메소드와 결합시키는 것이 좋다. 왜냐하면 데이터 저장 계층으로부터 읽어온 데이터를 사용하고 변경하는 등의 작업을 하는 곳이 서비스 계층이기 때문이다. 위와 같이 클래스 레벨에 트랜잭션 어노테이션을 붙여주면 메소드까지 적용이 된다.

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {

    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;

    public List<User> getUserList() {
        return userRepository.findAll();
    }

}

 

서비스 계층을 트랜잭션의 시작과 종료 경계로 정했다면, 테스트와 같은 특별한 이유가 아니고는 다른 계층이나 모듈에서 DAO에 직접 접근하는 것은 차단해야 한다. 트랜잭션은 보통 서비스 계층의 메소드 조합을 통해 만들어지기 때문에 DAO가 제공하는 주요 기능은 서비스 계층에 위임 메소드를 만들어둘 필요가 있다. 그리고 가능하면 다른 모듈의 DAO에 접근할 때는 서비스 계층을 거치도록 하는 것이 바람직하다.

 

⑤ 읽기 전용 트랜잭션의 공통화

클래스 레벨에는 공통적으로 적용되는 읽기전용 트랜잭션 어노테이션을 선언하고, 추가나 삭제 또는 수정이 있는 작업에는 쓰기가 가능하도록 별도로 @Transacional 어노테이션을 메소드에 선언하는 것이 좋다. 이를 체감하기는 힘들겠지만 약간의 성능적인 이점을 얻을 수 있다.

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {

    private final UserRepository userRepository;
    private final BCryptPasswordEncoder passwordEncoder;

    public List<User> getUserList() {
        return userRepository.findAll();
    }

    @Transactional
    public User signUp(final SignUpDTO signUpDTO) {
        final User user = User.builder()
                .email(signUpDTO.getEmail())
                .pw(passwordEncoder.encode(signUpDTO.getPw()))
                .role(UserRole.ROLE_USER)
                .build();

        return userRepository.save(user);
    }

}

 

⑥ 테스트의 롤백

트랜잭션 어노테이션을 테스트에 붙이면 테스트의 DB 커밋을 롤백해주는 기능이 있다.

DB와 연동되는 테스트를 할 때에는 DB의 상태와 데이터가 상당히 중요하다. 하지만 문제는 테스트에서 DB에 쓰기 작업을 하면 DB의 데이터가 바뀌는 것인데, 트랜잭션 어노테이션을 테스트에 활용하면 테스트를 진행하는 동안에 조작한 데이터를 모두 롤백하고 테스트를 진행하기 전의 상태로 만들어준다. 어떠한 경우에도 커밋을 하지 않기 때문에 테스트가 성공하거나 실패해도 상관이 없으며 심지어 예외가 발생해도 어떠한 문제가 발생하지 않는다. 강제로 롤백시키도록 설정되어 있기 때문이다.

@Transactional
@ExtendWith(SpringExtension.class)
@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

    @Test
    void findByEmailAndPw() {
        final User user = User.builder()
                .email("email")
                .pw("pw")
                .role(UserRole.ROLE_USER).build();
        userRepository.save(user);

        assertThat(userRepository.findAll().size()).isEqualTo(1);
    }

}

 

하지만 테스트 메소드 안에서 진행되는 작업을 하나의 트랜잭션으로 묶고는 싶지만 강제 롤백을 원하지 않을 수 있다. 테스트의 작업을 그대로 DB에 반영하고 싶다면 @Rollback(false)를 이용해주면 된다. @Rollback은 메소드에만 적용가능하므로, 클래스 레벨에 부여하기를 원한다면 @TransactionConfiguration(defaultRollback=false) 를 이용하고, 롤백을 원하는 메소드에 @Rollback(true)를 이용하면 된다.

 

물론 여기서 auto_increment나 sequence 등에 의해 증가된 값은 롤백이 되지 않는다. 그렇기 때문에 테스트를 위해서는 별도의 데이터베이스로 연결을 하거나 또는 H2와 같은 휘발성(인메모리) 데이터베이스를 사용하는 것이 좋다.

 

 

3. Spring이 제공하는 Transaction(트랜잭션) 핵심 기술

 

Spring은 트랜잭션과 관련된 3가지 핵심 기술을 제공하고 있다. 그 3가지 핵심 기술은 다음과 같다.

  1. 트랜잭션(Transaction) 동기화
  2. 트랜잭션(Transaction) 추상화
  3. AOP를 이용한 트랜잭션(Transaction) 분리

 

① 트랜잭션(Transaction) 동기화 

JDBC를 이용하는 개발자가 직접 여러 개의 작업을 하나의 트랜잭션으로 관리하려면 Connection 객체를 공유하는 등 상당히 불필요한 작업들이 많이 생길 것이다.

Spring은 이러한 문제를 해결하고자 트랜잭션 동기화(Transaction Synchronization) 기술을 제공하고 있다. 트랜잭션 동기화는 트랜잭션을 시작하기 위한 Connection 객체를 특별한 저장소에 보관해두고 필요할 때 꺼내쓸 수 있도록 하는 기술이다.

트랜잭션 동기화 저장소는 작업 쓰레드마다 Connection 객체를 독립적으로 관리하기 때문에, 멀티쓰레드 환경에서도 충돌이 발생할 여지가 없다. 그래서 다음과 같이 트랜잭션 동기화를 적용하게 된다.

// 동기화 시작
TransactionSynchronizeManager.initSynchronization();
Connection c = DataSourceUtils.getConnection(dataSource);

// 작업 진행

// 동기화 종료
DataSourceUtils.releaseConnection(c, dataSource);
TransactionSynchronizeManager.unbindResource(dataSource);
TransactionSynchronizeManager.clearSynchronization();

 

하지만 개발자가 JDBC가 아닌 Hibernate와 같은 기술을 쓴다면 위의 JDBC 종속적인 트랜잭션 동기화 코드들은 문제를 유발하게 된다. 대표적으로 Hibernate에서는 Connection이 아닌 Session이라는 객체를 사용하기 때문이다. 이러한 기술 종속적인 문제를 해결하기 위해 Spring은 트랜잭션 관리 부분을 추상화한 기술을 제공하고 있다.

 

② 트랜잭션(Transaction) 추상화

Spring은 트랜잭션 기술의 공통점을 담은 트랜잭션 추상화 기술을 제공하고 있다. 이를 이용함으로써 애플리케이션에 각 기술마다(JDBC, JPA, Hibernate 등) 종속적인 코드를 이용하지 않고도 일관되게 트랜잭션을 처리할 수 있도록 해주고 있다.

 

Spring이 제공하는 트랜잭션 경계 설정을 위한 추상 인터페이스는 PlatformTransactionManager 이다. 예를 들어 만약 JDBC의 로컬 트랜잭션을 이용한다면 DataSourceTxManager를 이용하면 된다.

이제 우리는 사용하는 기술과 무관하게 PlatformTransactionManager를 통해 다음의 코드와 같이 트랜잭션을 공유하고, 커밋하고, 롤백할 수 있게 되었다.

public Object invoke(MethodInvoation invoation) throws Throwable {
	TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
	
	try {
		Object ret = invoation.proceed();
		this.transactionManager.commit(status);
		return ret;
	} catch (Exception e) {
		this.transactionManager.rollback(status);
		throw e;
	}
}

 

하지만 위와 같은 트랜잭션 관리 코드들이 비지니스 로직 코드와 결합되어 2가지 책임을 갖고 있다. Spring에서는 AOP를 이용해 이러한 트랜잭션 부분을 핵심 비지니스 로직과 분리하였다.

 

③ AOP를 이용한 트랜잭션(Transaction) 분리 

 

예를 들어 다음과 같이 트랜잭션 코드와 비지니스 로직 코드가 복잡하게 얽혀있는 코드가 있다고 하자.

public void addUsers(List<User> userList) {
	TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
	
	try {
		for (User user: userList) {
			if(isEmailNotDuplicated(user.getEmail())){
				userRepository.save(user);
			}
		}

		this.transactionManager.commit(status);
	} catch (Exception e) {
		this.transactionManager.rollback(status);
		throw e
	}
}

 

위의 코드는 여러 책임을 가질 뿐만 아니라 서로 성격도 다르고 주고받는 것도 없으므로 분리하는 것이 적합하다.

하지만 위의 코드를 어떻게 분리할 것인지에 대한 고민을 해야 한다. 흔히 떠올릴 수 있는 방법으로는 내부 메소드로 추출하거나 DI로 합성을 이용해 해결하거나 상속을 이용할 수 있을 것이다.

하지만 위의 어떠한 방법을 이용하여도 트랜잭션을 담당하는 기술 코드를 완전히 분리시키는 것이 불가능하였다. 그래서 Spring에서는 마치 트랜잭션 코드와 같은 부가 기능 코드가 존재하지 않는 것 처럼 보이기 위해 해당 로직을 클래스 밖으로 빼내서 별도의 모듈로 만드는 AOP(Aspect Oriented Programming, 관점 지향 프로그래밍)를 고안 및 적용하게 되었고, 이를 적용한 트랜잭션 어노테이션(@Transactional)을 지원하게 되었다. 이를 적용하면 위와 같은 코드를 핵심 비지니스 로직만 다음과 같이 남길 수 있다.

@Service
@RequiredArgsConstructor
@Transactional
public class UserService {

    private final UserRepository userRepository;

    public void addUsers(List<User> userList) {
        for (User user : userList) {
            if (isEmailNotDuplicated(user.getEmail())) {
                userRepository.save(user);
            }
        }
    }
}

 

④ Spring 트랜잭션의 세부 설정 

Spring의 DefaultTransactionDefinition이 구현하고 있는 TransactionDefinition 인터페이스는 트랜잭션의 동작방식에 영향을 줄 수 있는 네 가지 속성을 정의하고 있다. 해당 4가지 속성은 트랜잭션을 세부적으로 이용할 수 있게 도와주며, @Transactional 어노테이션에도 공통적으로 적용할 수 있다. 

 

  • 트랜잭션 전파
  • 격리수준
  • 제한시간
  • 읽기전용

 

트랜잭션 전파

트랜잭션 전파란 트랜잭션의 경계에서 이미 진행중인 트랜잭션이 있거나 없을 때 어떻게 동작할 것인가를 결정하는 방식을 의미한다. 예를 들어 어떤 A 작업에 대한 트랜잭션이 진행중이고 B 작업이 시작될 때 B 작업에 대한 트랜잭션을 어떻게 처리할까에 대한 부분이다.

 

1. A의 트랜잭션에 참여(PROPAGATION_REQUIRED)

B의 코드는 새로운 트랜잭션을 만들지 않고 A에서 진행중이 트랜잭션에 참여할 수 있다. 이 경우 B의 작업이 마무리 되고 나서, 남은 A의 작업(2)을 처리할 때 예외가 발생하면 A와 B의 작업이 모두 취소된다. 왜냐하면 A와 B의 트랜잭션이 하나로 묶여있기 때문이다.

 

2. 독립적인 트랜잭션 생성(PROPAGATION_REQUIRES_NEW)

반대로 B의 트랜잭션은 A의 트랜잭션과 무관하게 만들 수 있다. 이 경우 B의 트랜잭션 경계를 빠져나오는 순간 B의 트랜잭션은 독자적으로 커밋 또는 롤백되고, 이것은 A에 어떠한 영향도 주지 않는다. 즉, 이후 A가 (2)번 작업을 하면서 예외가 발생해 롤백되어도 B의 작업에는 영향을 주지 못한다.

 

3. 트랜잭션 없이 동작(PROPAGATION_NOT_SUPPORTED)

B의 작업에 대해 트랜잭션을 걸지 않을 수 있다. 만약 B의 작업이 단순 데이터 조회라면 굳이 트랜잭션이 필요 없을 것이다.

 

이렇듯 이미 진행중인 트랜잭션이 어떻게 영향을 미칠 수 있는가에 대한 부분이 트랜잭션 전파 속성이다. 트랜잭션을 시작하는 것처럼 보이는 getTransaction() 코드가 begin이 아닌 get으로 이름이 지어진 이유도 여기에 있다. 해당 트랜잭션은 다른 트랜잭션에 묶여있을 수 있기 때문이다. 위에서 설명한 대표적인 처리 방법 외에도 다양한 처리 방법을 지원하고 있다.

 

 

격리 수준

모든 DB 트랜잭션은 격리수준을 가지고 있어야 한다. 서버에서는 여러 개의 트랜잭션이 동시에 진행될 수 있는데, 모든 트랜잭션을 독립적으로 만들고 순차 진행 한다면 안전하겠지만 성능이 크게 떨어질 수 밖에 없다. 따라서 적절하게 격리수준을 조정해서 가능한 많은 트랜잭션을 동시에 진행시키면서 문제가 발생하지 않도록 제어해야 한다. 이는 JDBC 드라이버나 DataSource 등에서 재설정할 수 있고, 트랜잭션 단위로 격리 수준을 조정할 수도 있다.

DefaultTransactionDefinition에 설정된 격리수준은 ISOLATION_DEFAULT로 DataSource에 정의된 격리 수준을 따른다는 것이다.

기본적으로는 DB나 DataSource에 설정된 기본 격리 수준을 따르는 것이 좋지만, 특별한 작업을 수행하는 메소드라면 독자적으로 지정해줄 필요가 있다.

 

 

제한시간

트랜잭션을 수행하는 제한시간을 설정할 수 있다. 제한시간의 설정은 트랜잭션을 직접 시작하는 PROPAGATION_REQUIRED나 PROPAGATION_REQUIRES_NEW의 경우에 사용해야만 의미가 있다.

 

 

읽기전용

읽기전용으로 설정해두면 트랜잭션 내에서 데이터를 조작하는 시도를 막아줄 수 있을 뿐만 아니라 데이터 액세스 기술에 따라 성능이 향상될 수 있다.

 

 

위에서 트랜잭션의 세부 설정들 외에도 Spring은 다양한 세부 설정들을 제공하고 있다. 이와 관련된 자세한 내용은 다음 포스팅에서 참고할 수 있다.

 


[참고 자료] 

 

망나니 개발자님 어떤 분일까.. 진짜 블로그 글들이 주옥같다. 구독합니다 망개님 

https://mangkyu.tistory.com/50

 

[Spring] Transaction(트랜잭션)이란?

오늘은 단일 쿼리로는 해결할 수 없는 로직을 처리할 때 필요한 개념인 트랜잭션에 대해 알아보고, Spring에서 어떻게 활용하는지 확인해보도록 하겠습니다. 1. Transaction(트랜잭션)이란? [ Transaction

mangkyu.tistory.com

 

 

'Coding > Spring' 카테고리의 다른 글

[31] CORS  (0) 2022.12.18
[30] Spring 심화주차 키워드정리  (0) 2022.12.18
[27] Spring AOP  (0) 2022.12.14
[26] OAuth / 소셜 로그인  (0) 2022.12.14
[25] JPA 다양한 연관관계 매핑  (0) 2022.12.13

 

과제를 수행하다 보니 자바 기초가 너무 부족한 것 같아서 다시 한번 개념 정리를 하고 넘어가려 한다.

객체란 무엇이고 클래스는 무엇이며, 필드 생성자 메소드의 역할을 다시 정리해보자.


객체지향 언어

① 객체 지향의 4대 특성

  • 캡 - 캡슐화(Encapsulation): 정보 은닉(information hiding)
  • 상 - 상속(Inheritance): 재사용
  • 추 - 추상화(Abstraction): 모델링
  • 다 - 다형성(Polymorphism): 사용 편의

※ 객체 지향 프로그래밍은 만들고자 하는 완성품인 객체를 모델링하고, 집합 관계에 있는 부품 객체와 사용 관계에 있는 객체를 하나씩 설계한 후 조립하는 방식으로 프로그램을 개발하는 기법이다.

 

② 클래스의 정의 

  • 분류, 집합. 같은 속성과 기능을 가진 객체를 총칭하는 개념
  • 자바에서는 설계도가 클래스이다.
  • 클래스에는 객체를 생성하기 위한 필드와 메소드가 정의되어 있다.
  • 클래스로부터 만들어진 객체를 해당 클래스의 인스턴스라고 한다.

 

③ 객체의 정의 : 세상에 존재하는 유일무이한 사물

-> 세상에 존재하는 유일 무이한 객체를 특성(속성+기능)에 따라 분류해 보니 객체를 통칭할 수 있는 집합적 개념, 클래스(분류)가 나오게 된다.

 

④ 추상화 : 구체적인 것을 분해해서 관심 영역(애플리케이션 경계 Application Boundary)에 있는 특성만 가지고 재조합하는 것 = 모델링

  • OOP의 추상화는 모델링이다.
  • 클래스 : 객체 = 사람 : 김연아 = 펭귄 : 뽀로로
  • 클래스 설계에서 추상화가 사용된다.
  • 클래스 설계를 위해서는 애플리케이션 경계부터 정해야 한다.
  • 객체 지향에서 추상화의 결과는 클래스이다.

더 확장해서 추상화를 본다면 다음과 같이 볼 수 있다.

  • 상속을 통한 추상화, 구체화
  • 인터페이스를 통한 추상화
  • 다형성을 통한 추상화

 

⑤ 클래스의 구성 멤버

 

1. 필드 : 객체의 속성을 의미한다.

  • 객체의 고유 데이터, 부품 객체, 상태 정보를 저장하는 곳
  • 선언 형태는 변수와 비슷하지만, 필드를 변수라고 하지 않는다.
  • 변수는 생성자와 메소드 내에서만 사용되고 생성자와 메소드가 실행 종료되면 자동 소멸되지만 필드의 경우 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 객체외 함께 존재한다.

 

2. 생성자 : 객체 생성 시 초기화 담당

  • 생성자는 new 연산자로 호출되는 특별한 중괄호{} 블록이다.
  • 필드를 초기화하거나 메소드를 호출해서 객체를 사용할 준비를 한다.
  • 생성자는 메소드와 비슷하게 생겼지만 클래스 이름으로 되어 있고 리턴 타입이 없다.

 

3. 메서드 : 객체의 동작을 의미한다.

  • 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다.
  • 메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다.
  • 메소드는 객체 간의 데이터를 전단하는 수단이다.
  • 외부로부터 매개값을 받아 실행에 이용하고, 실행 후 결과 값을 외부로 리턴할 수도 있다.

 

오버로딩 오버라이딩

객체 지향에서 다형성이라고 하면 오버라이딩(Overriding)과 오버로딩(Overloading)이라고 할 수 있다.

  • 다형성 : 사용편의성
  • 오버로딩 : 같은 메서드 이름, 다른 인자 목록으로 다수의 메서드를 중복 정의
  • 오버라이딩 : 같은 메서드 이름, 같은 인자 목록으로 상위 클래스의 메서드를 재정의

 

변수와  메모리 구조

T메모리는 스태틱 영역, 스택 영역, 힙 영역으로 구성된다.

http://www.tcpschool.com/c/c_memory_structure

  • 지역 변수스택 영역에서  일생을 보낸다. 그것도 스택 프레임 안에서 일생을 보내게 된다. 따라서 스택 프레임이 사라지면 함께 사라진다.
  • 클래스 멤버 변수스태틱 영역에서 일생을 보낸다. 스태틱 영역에 한번 자리 잡으면 JVM이 종료될 때까지 고정된(static)상태로 그 자리를 지킨다.
  • 객체 변수에서 일생을 보낸다. 객체 멤버 변수들은 객체와 함께 가비지 컬렉터라고 하는 힙 메모리 회수기에 의해 일생을 마치게 된다.

전역변수 사용을 지양하는 이유

  • 전역 변수는 코드 어느 곳에서나 접근할 수 있다고 해서 전역 변수라고 하고, 여러 메서드들이 공유해서 사용한다고 해서 공유 변수라고도 한다.
  • 프로젝트 큐모에 따라 모드가 커지면서 여러 메서드에서 전역 변수의 값을 변경하기 시작하면 T메모리로 추적하지 않는 이상 전역 변수에 저장돼 있는 값을 파악하기 쉽지 않다.
  • 따라서 최대한 전역 변수는 피할 수 있다면 피해야할 존재이다.
  • 대신 잃기 전용으로 값을 공유해서 전역 상수로 쓰는 것은 좋은 방법이다. 대표적인 예로 원주율을 나타내는 PI가 있다.

참고 자료 :

 

<스프링 입문을 위한 자바 객체 지향의 원리와 이해> 김종민 지음

<혼자 공부하는 자바> 신용권 지음

'Coding > Java' 카테고리의 다른 글

[29] JAVA 스레드 제어  (0) 2022.12.21
[28] JAVA 멀티스레드  (0) 2022.12.21
[26] JAVA 익명 객체 (Anonymous)  (0) 2022.12.10
[25] JAVA 중첩 클래스/ 중첩 인터페이스  (0) 2022.12.09
[24] JAVA 타입 변환과 다형성  (0) 2022.12.06

+ Recent posts