인증과 인가의 차이

  • 인증(Authentication) : 해당 유저가 실제 유저인지 인증하는 개념. 스마트폰에 지문인식, 이용하는 사이트에 로그인 등과 같이, 실제 그 유저가 맞는지를 확인하는 절차를 의미한다. 일반적으로 웹 어플리케이션은 아래 설명할 두가지 방법을 통해서 인증을 처리한다. 
  • 인가(Authorization) : 해당 유저가 특정 리소스에 접근이 가능한지 허가를 확인하는 개념. 예를들어 관리자 페이지-관리자 권한 같은 것들이 해당된다.

 

웹 어플리케이션 인증의 특수성

  1. 일반적으로 서버-클라이언트 구조로 되어있고, 실제로 이 두가지 요소는 아주 멀리 떨어져 있다.
  2. 그리고 Http 라는 프로토콜을 이용하여 통신하는데, 그 통신은 비연결성(Connectionless) 무상태(Stateless)로 이루어진다.
  3. 보통 모바일/웹 서비스의 인증은 HTTP 메세지의 헤더에 인증 수단을 넣어 요청을 보낸다.

비연결성(Connectionless) 무상태(Stateless) 의미 ↓

더보기

비연결성(Connectionless)서버와 클라이언트가 연결되어 있지 않다는 것. 채팅이나 게임 같은 것들을 하지 않는 이상 서버와 클라이언트는 실제로 연결되어 있지 않다. 그 이유는 리소스를 절약하기 위해서 인데, 만약 서버와 클라이언트가 실제로 계속 연결되어있다면 클라이언트는 그렇다고 쳐도, 서버의 비용이 기하급수적으로 늘어나기 때문. 그래서 서버는 실제로 하나의 요청에 하나의 응답을 내버리고 연결을 끊어버리고있다 라고 생각하면 된다.

 

무상태(Stateless)서버가 클라이언트의 상태를 저장하지 않는다는 것. 기존의 상태를 저장하는 것들도 마찬가지로 서버의 비용과 부담을 증가시키는 것 이기 때문에 기존의 상태가 없다고 가정하는 프로토콜을 이용해 구현되어 있다. 실제로 서버는 클라이언트가 직전에, 혹은 그 전에 어떠한 요청을 보냈는지 관심도 없고 전혀 알지 못한다.

 

인증방식 (1) 쿠키 - 세션 방식

 

https://tansfil.tistory.com/58

  • 쿠키-세션 방식은 서버가 특정 유저가 로그인 되었다는 상태를 저장하는 방식
  • 세션은 서버에서 가지고 있는 정보이며 쿠키는 사용자에게 발급된 세션을 열기 위한 열쇠(SESSION ID)를 의미
  • 인증과 관련된 아주 약간의 정보만 서버가 가지고 있게 되고 유저의 이전 상태의 전부는 아니더라도 인증과 관련된 최소한의 정보는 저장해서 로그인을 유지시킨다는 개념
  • 결과적으로 Session/Cookie 인증 방식을 사용하는 이유는 서버에 인증의 책임을 전가하는 것이다.
  • 더보기
    1. 사용자가 로그인 요청을 보냅니다.
    2. 서버는 DB의 유저 테이블을 뒤져서 아이디 비밀번호를 대조해봐야겠죠?
    3. 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 “세션 저장소”에 해당 유저가 로그인 되었다는 정보를 넣습니다.
    4. 세션 저장소에서는 유저의 정보와는 관련 없는 난수인 session-id를 발급합니다.
    5. 서버는 로그인 요청의 응답으로 session-id를 내어줍니다.
    6. 클라이언트는 그 session-id를 쿠키라는 저장소에 보관하고 앞으로의 요청마다 세션아이디를 같이 보냅니다. (주로 HTTP header에 담아서 보냅니다!)
    7. 클라이언트의 요청에서 쿠키를 발견했다면 서버는 세션 저장소에서 쿠키를 검증합니다.
    8. 만약 유저정보를 받아왔다면 이 사용자는 로그인이 되어있는 사용자겠죠?
    9. 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.아래는 그림의 각 번호에 따른 설명

 

 

 


① 장점

  1. 세션/쿠키 방식은 기본적으로 쿠키를 매개로 인증을 거치기 때문에 비교적 안전한 방식이다.
    • 여기서 쿠키는 세션 저장소에 담긴 유저 정보를 얻기 위한 열쇠를 의미한다.
    • 따라서 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체(세션 ID)는 유의미한 값을 갖고있지 않다(중요 정보는 서버 세션)
    • 헤더에 직접적으로 계정정보를 담아 인증을 거치는 것 보단 안전하다.
  2. 사용자 A는 1번, 사용자 B는 2번 이런식으로 고유의 ID값을 발급받게 된다. 그렇게 되면 서버에서는 쿠키 값을 받았을 때 일일이 회원정보를 확인할 필요 없이 바로 어떤 회원인지를 확인할 수 있어 서버의 자원에 접근하기 용이하다.

② 단점

  1. 장점 1에서 쿠키를 탈취당하더라도 안전할 수 있다고 언급했지만 문제가 하나 있다. 만일 A 사용자의 HTTP 요청을 B 사용자(해커)가 가로챘다면 그 안에 들어있는 쿠키도 충분히 훔칠 수 있다. 그리고 B 사용자는 그 훔친 쿠키를 이용해 HTTP 요청을 보내면 서버의 세션저장소에서는 A 사용자로 오인해 정보를 잘못 뿌려주게 된다.(세션 하이재킹 공격이라고 한다) 
    • 해결책 ↓
    • 더보기
      1. HTTPS를 사용해 서버와 클라이언트 간의 주고받는 정보를 암호화하여 요청 자체를 탈취해도 안의 정보를 읽기 힘들게 한다. 2. 세션에 유효시간을 넣어준다. 
  2. 서버에서 세션 저장소를 사용한다. 따라서 서버에서 추가적인 저장공간을 필요로 하게되고 자연스럽게 부하도 높아질 것. 

 

인증 방식 (2) JWT 기반 인증

https://tansfil.tistory.com/58

 

  • JWT(JSON Web Token)란 인증에 필요한 정보들을 암호화시킨 토큰을 의미
  • JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT 토큰(Access Token)을 HTTP 헤더에 실어 서버가 클라이언트를 식별한다.
  • 아래는 그림의 각 번호에 따른 설명 
  • 더보기
    1. 사용자가 로그인 요청을 보냅니다.
    2. 서버는 DB의 유저 테이블을 뒤져서 아이디 비밀번호를 대조해봐야겠죠?
    3. 실제 유저테이블의 정보와 일치한다면 인증을 통과한 것으로 보고 유저의 정보를 JWT로 암호화 해서 내보냅니다
    4. 서버는 로그인 요청의 응답으로 jwt 토큰을 내어줍니다.
    5. 클라이언트는 그 토큰을 저장소에 보관하고 앞으로의 요청마다 토큰을 같이 보냅니다.
    6. 클라이언트의 요청에서 토큰을 발견했다면 서버는 토큰을 검증합니다.
    7. 이후에는 로그인 된 유저에 따른 응답을 내어줍니다.

① 장점
  1. 간편하다. 세션/쿠키는 별도의 저장소의 관리가 필요하다. 그러나 JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없다. 이는 Stateless 한 서버를 만드는 입장에서는 큰 강점이다. 여기서 Stateless는 어떠한 별도의 저장소도 사용하지 않는, 즉 상태를 저장하지 않는 것을 의미. 이는 서버를 확장하거나 유지,보수하는데 유리하다.
  2. 확장성이 뛰어나다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다. 예를 들어 Facebook 로그인, Google 로그인, 카카오 OAuth2 로그인 등은 모두 토큰을 기반으로 인증을 한다. 이에 선택적으로 이름이나 이메일 등을 받을 수 있는 권한도 받을 수 있다.
  3. 동시 접속자가 많을 때 서버 측 부하를 낮춰줄 수 있다.

② 단점

  1. 이미 발급된 JWT에 대해서는 돌이킬 수 없다. 세션/쿠키의 경우 만일 쿠키가 악의적으로 이용된다면, 해당하는 세션을 지워버리면 된다. 하지만 JWT는 한 번 발급되면 유효기간이 완료될 때 까지는 계속 사용이 가능하다. 따라서 악의적인 사용자는 유효기간이 지나기 전까지 신나게 정보들을 털어갈 수 있다. 
    • 해결책 ↓
    • 더보기
      기존의 Access Token의 유효기간을 짧게 하고 Refresh Token이라는 새로운 토큰을 발급한다. 그렇게 되면 Access Token을 탈취당해도 상대적으로 피해를 줄일 수 있다.
  2. Payload 정보가 제한적이다. 위에서 언급했다시피 Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있다. (세션/쿠키 방식에서는 유저의 정보가 전부 서버의 저장소에 안전하게 보관된다) 따라서 유저의 중요한 정보들은 Payload에 넣을 수 없다.
  3. JWT의 길이. 세션/쿠키 방식에 비해 JWT의 길이는 길다. 따라서 인증이 필요한 요청이 많아질 수록 서버의 자원낭비가 발생하게 된다. = 비용 증가
  4. 구현의 복잡도가 증가한다.
  5. Secret key 유츌 시 JWT 조작 가능하다.

 

 

쿠키세션과 JWT의 차이

  • 가장 큰 차이점은 세션/쿠키는 세션 저장소에 유저의 정보를 넣는 반면, JWT는 토큰 안에 유저의 정보들이 넣는다는 점
  • 물론 클라이언트 입장에서는 HTTP 헤더에 세션ID나 토큰을 실어서 보내준다는 점에서는 동일하나, 서버 측에서는 인증을 위해 암호화를 하냐, 별도의 저장소를 이용하냐는 차이가 발생한다.

 


자료 출처 :

개인 과제 질문

 

1. 처음 설계한 API와 ERD에 변경사항이 있었나요? 변경되었다면 어떤 점 때문일까요? 첫 설계의 중요성에 대해 생각해보세요.

과제 레벨 1 까지만 구현했기 때문에 처음 설계한 API와 ERD에 큰 변경사항은 없었지만, 만약 레벨2로 넘어가야 했다면, 게시문의 댓글을 담당하는 Comment Entity를 하나 더 생성하고 FK를 이용해 게시글과 맵핑해주는 작업을 추가하는 수정이 필요했을 것 같다.


2. ERD를 먼저 설계한 후 Entity를 개발했을 때 어떤 점이 도움이 되셨나요?
 

ERD(Entity Relationship Diagram)

  • 엔티티와 이들 간의 관계를 알기 쉽게 약속된 도형을 이용하여 일목요연하게 그림으로 표현한 것이다.
  • ER모델의 구성요소는 엔티티(Entity), 관계(Relationship), 속성(Attribute) 을 기본으로 하여 관계 수, 식별자, 서브타입 등으로 세분화 할 수 있다.
  • 문장 형식의 업무 처리 규정을 약속된 도형 형태로 나타내어 전체 업무 및 데이터의 구조를 쉽게 파악할 수 있다.
  • 문장으로 기술하지 않고 공통적인 약속을 통해 표현함으로써 업무의 파악과 이해가 용이하다.
  • 데이터베이스를 구현할 때 정규화(Normalization)된 테이블을 만들기 위한 근거 자료로 활용한다.

3. JWT를 사용하여 인증/인가를 구현 했을 때의 장점은 무엇일까요?

  1. 간편하다. 세션/쿠키는 별도의 저장소의 관리가 필요하다. 그러나 JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없다. 이는 Stateless 한 서버를 만드는 입장에서는 큰 강점이다. 여기서 Stateless는 어떠한 별도의 저장소도 사용하지 않는, 즉 상태를 저장하지 않는 것을 의미. 이는 서버를 확장하거나 유지,보수하는데 유리하다.
  2. 확장성이 뛰어나다. 토큰 기반으로 하는 다른 인증 시스템에 접근이 가능하다. 예를 들어 Facebook 로그인, Google 로그인, 카카오 OAuth2 로그인 등은 모두 토큰을 기반으로 인증을 한다. 이에 선택적으로 이름이나 이메일 등을 받을 수 있는 권한도 받을 수 있다.
  3. 동시 접속자가 많을 때 서버 측 부하를 낮춰줄 수 있다.

4. 반대로 JWT를 사용한 인증/인가의 한계점은 무엇일까요?

  1. 이미 발급된 JWT에 대해서는 돌이킬 수 없다. 세션/쿠키의 경우 만일 쿠키가 악의적으로 이용된다면, 해당하는 세션을 지워버리면 된다. 하지만 JWT는 한 번 발급되면 유효기간이 완료될 때 까지는 계속 사용이 가능하다. 따라서 악의적인 사용자는 유효기간이 지나기 전까지 신나게 정보들을 털어갈 수 있다. 
  2. Payload 정보가 제한적이다. 위에서 언급했다시피 Payload는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있다. (세션/쿠키 방식에서는 유저의 정보가 전부 서버의 저장소에 안전하게 보관된다) 따라서 유저의 중요한 정보들은 Payload에 넣을 수 없다.
  3. JWT의 길이. 세션/쿠키 방식에 비해 JWT의 길이는 길다. 따라서 인증이 필요한 요청이 많아질 수록 서버의 자원낭비가 발생하게 된다. = 비용 증가
  4. 구현의 복잡도가 증가한다.
  5. Secret key 유츌 시 JWT 조작 가능하다.

5. 만약 댓글 기능이 있는 블로그에서 댓글이 달려있는 게시글을 삭제하려고 한다면 무슨 문제가 발생할까요? Database 테이블 관점에서 해결방법이 무엇일까요?
 

게시글에 달려있는 댓글 또한 동시에 삭제해야 한다. @OneToMany(cascade= CASCADE.REMOVE)를 사용하여 게시글이 삭제 될 때 그와 연관된 여러개의 댓글도 동시에 삭제되도록 해결할 수 있을 것 같다.


6. IoC / DI 에 대해 간략하게 설명해 주세요!
 

DI(Dependency Injection)

  • DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능이다.
  • 객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다.
  • DI(의존성 주입)를 통해서 모듈 간의 결합도가 낮아지고 유연성이 높아진다.

Ioc(Inversion of Control)

  • IoC(Inversion of Control)란 "제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.
  • IoC는 제어의 역전이라고 말하며, 간단히 말해 "제어의 흐름을 바꾼다"라고 한다.
  • 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.

Spring 공통 질문

1. 스프링 프레임워크

[19] 스프링 프레임워크

 

[19] 스프링 프레임워크

스프링 프레임워크 ① 스프링 프레임워크(Spring Framework) 여러 프레임워크들 중 자바(JAVA)를 기반으로 하는 프레임워크 이다. 대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자

leejincha.tistory.com

 

2. 스프링에서 DI (의존성 주입) 를 사용하는 이유

[20] 의존성 주입 DI(Dependency Injection)

 

[20] 의존성 주입 DI(Dependency Injection)

스프링에서 DI (의존성 주입) 를 사용하는 이유 ① DI(의존성 주입)이란? DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계

leejincha.tistory.com


3. ORM, JPA, Spring Data JPA 

[21] ORM, JPA, Spring Data JPA

 

[21] ORM, JPA, Spring Data JPA

ORM, JPA, Spring Data JPA ORM : 객체(Object)와 관계형 데이터(Relational data) 를 매핑하기 위한 기술이다. 객체와 테이블 관계를 바탕으로 SQL문장을 자동으로 생성하여 객체로 DB를 조작하게 하는 기술. JPA :

leejincha.tistory.com


인증, 인가의 차이

[18] 인증과 인가 (1) 세션/쿠키, JWT

 

[18] 인증과 인가 (1) 세션/쿠키, JWT

인증과 인가의 차이 인증(Authentication) : 해당 유저가 실제 유저인지 인증하는 개념. 스마트폰에 지문인식, 이용하는 사이트에 로그인 등과 같이, 실제 그 유저가 맞는지를 확인하는 절차를 의미

leejincha.tistory.com

참고자료 : https://jake-seo-dev.tistory.com/76


절차지향 프로그래밍, 객체지향 프로그래밍, 관점지향 프로그래밍 

 

① 절차지향 프로그래밍 (Procedural Programming)

  1. 컴퓨터가 해야 할 일을 시간의 흐름에 따라 순차적으로 프로그래밍하는 방식
  2. 장점
    1. 객체나 클래스를 만들 필요 없이 바로 프로그램을 코딩할 수 있어서 시간적으로 유리하다.
    2. 필요한 기능을 함수로 만들어 두기 때문에 같은 코드를 복사하지 않고 호출하여 사용할 수 있다.
    3. 프로그램의 흐름을 쉽게 추적할 수 있다.
  3. 단점
    1. 각 코드가 매우 유기성이 높기 때문에 수정하기가 힘들다. (새로운 데이터나 기능을 추가하기가 어려움)
    2. 프로그램 전체에서 코드를 재사용 할 수가 없어 프로젝트 개발 비용과 시간이 늘어날 수 있다.
    3. 유지보수 및 디버깅이 어렵다.

 

② 객체지향 프로그래밍 (Object-Oriented Programming)

  • 데이터와 기능(함수)들을 묶어 하나의 객체로 만들어 진행하는 방식 / 하나의 사물 (객체) 에 하나의 의미를 부여하는 것처럼 프로그래밍
  • 장점
    1. 모듈화, 캡슐화로 하드웨어가 같은 기능을 중복으로 연산하지 않도록해 유지보수에 용이하다.
    2. 모듈을 재활용 하기 때 문에 하드웨어의 처리양을 획기적으로 줄여줌.
    3. 객체지향적이기 때문에 현실 세계와 유사성에 의해 코드를 이해하기 쉽게 만든다.
    4. 객체는 그 자체가 하나의 프로그램이기 때문에 다른 프로그램에서 재사용이 가능하다.
  • 단점
    1. 대부분의 객체 지향 프로그램은 속도가 상대적으로 절차지향보다 느려지고 많은 양의 메모리를 사용하는 경향이 있다.
    2. 설계 과정에 시간이 많이 투자된다.

 

③ 관점지향 프로그래밍 (Aspect-Oriented Programming)

  1. 객체지향을 더욱 발전 시키기 위한 개념의 하나. 하나의 소프트웨어가 하나의 거대한 OOP로써 설계, 프로 그래밍 되었다면 이것을 각 기능별로 모듈화 해서 분리 시키는 개념.
  2. 관점지향의 핵심은 공통 모듈을 분리시켜 해당 소스 코드가 외부의 다른 클래스에서 존재하는 것.
  3. 장점
    1. 각 비즈니스 로직마다 복붙을 통해 생겨난 중복 코드가 사라진다.
    2. 각 비즈니스 로직을 구현하는 개발자는 자기 자신의 비즈니스 코드에만 집중할 수 있어 코드가 간결해지고, 유지보수가 쉬워진다.
    3. 재활용성이 더욱 높아진다.
  • CORE CONCERN(핵심관심): 각 서비스의 핵심 비즈니스 로직예: 계좌이체, 입출금, 이자계산
  • Crosscut Concern(횡단관심): 공통 모듈예: 보안, 예외처리, 로깅 등
  •  

팀 질문 ( 키워드 5개)

생성자 자동완성 어노테이션

@NoArgsConstructor

기본 생성자를 생성해준다.

이 경우 초기값 세팅이 필요한 final 변수가 있을 경우 컴파일 에러가 발생함으로 주의한다.

@NoArgsConstructor(force=true) 를 사용하면 null, 0 등 기본 값으로 초기화 된다.

 

@RequiredArgsConstructor

final 변수, Notnull 표시가 된 변수처럼 필수적인 정보를 세팅하는 생성자를 만들어준다.

 

@AllArgsConstructor

전체 변수를 생성하는 생성자를 만들어준다.

 

참고 자료 : https://minji6119.tistory.com/44


영속성 컨텍스트란?

  • 영속성 컨텍스트란 엔티티를 영구 저장 하는 환경 이라는 뜻
  • 어플리케이션(자바 코드 그 자체)이 데이터베이스에서 꺼내온 데이터 객체를 보관하는 역할을 한다.
  • 영속성 컨텍스트는 엔티티 매니저를 통해 엔티티를 조회하거나 저장할때 엔티티를 보관하고 관리한다.
  • 엔티티 매니저마다 개별적으로 부여되는, 어떠한 논리적 공간같은 개념으로 비유적으로 이해할 수 있다.
  • 자바의 엔티티 객체를 엔티티 매니저마다 가지고 있는 영속성 컨텍스트라는 공간에다 넣고 빼고 하면서 사용하는 것
  • “영속화 한다” 라는 말을 “엔티티 매니저가 자기의 영속성 컨텍스트에 넣어준다”로 이해할 수 있다.

Refresh token과 Access token

 

Access Token(JWT)를 통한 인증 방식의 문제는 만일 제 3자에게 탈취당할 경우 보안에 취약하다는 점입니다.

더보기

유효기간이 짧은 Token의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 Token을 발급받아야 하므로 불편합니다.

그러나 유효기간을 늘리자면, 토큰을 탈취당했을 때 보안에 더 취약해지게 됩니다. 

이때 “그러면 유효기간을 짧게 하면서  좋은 방법이 있지는 않을까?”라는 질문의 답이 바로 "Refresh Token"입니다. 

해결법 

Refresh Token은 Access Token과 똑같은 형태의 JWT입니다. 처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서, Access Token이 만료됐을 때 새로 발급해주는 열쇠가 됩니다(여기서 만료라는 개념은 그냥 유효기간을 지났다는 의미입니다.) 

 

사용 예

더보기

Refresh Token의 유효기간은 2주, Access Token의 유효기간은 1시간이라 하겠습니다. 사용자는 API 요청을 신나게 하다가 1시간이 지나게 되면, 가지고 있는 Access Token은 만료됩니다. 그러면 Refresh Token의 유효기간 전까지는 Access Token을 새롭게 발급받을 수 있습니다. 

 

* Access Token은 탈취당하면 정보가 유출되는건 동일합니다. 다만 짧은 유효기간 안에만 사용이 가능하기에 더 안전하다는 의미입니다. 

 * Refresh Token의 유효기간이 만료됐다면, 사용자는 새로 로그인해야 합니다. Refresh Token도 탈취될 가능성이 있기 때문에 적절한 유효기간 설정이 필요해보입니다(보통 2주로 많이 잡더군요)

 

 

참고 자료 : https://tansfil.tistory.com/59?category=475681


JWT 장단점

장점

  • 동시 접속자가 많을 때 서버 측 부하 낮춤
  • Client, Sever 가 다른 도메인을 사용할 때 - 예) 카카오 OAuth2 로그인 시 JWT Token 사용

단점

  • 구현의 복잡도 증가
  • JWT 에 담는 내용이 커질 수록 네트워크 비용 증가 (클라이언트 → 서버)
  • 기 생성된 JWT 를 일부만 만료시킬 방법이 없음
  • Secret key 유출 시 JWT 조작 가능

느슨한 결합 / 강한 결합 

강한 결합

객체 내부에서 다른 객체를 생성하는 것은 강한 결합도를 가지는 구조이다. A 클래스 내부에서 B 라는 객체를 직접 생성하고 있다면, B 객체를 C 객체로 바꾸고 싶은 경우에 A 클래스도 수정해야 하는 방식이기 때문에 강한 결합이다.

 

느슨한 결합

객체를 주입 받는다는 것은 외부에서 생성된 객체를 인터페이스를 통해서 넘겨받는 것이다. 이렇게 하면 결합도를 낮출 수 있고, 런타임시에 의존관계가 결정되기 때문에 유연한 구조를 가진다.

강한 결합에서 느슨한 결합으로 바뀌는 것을 IoC(제어 반전)이라고 하고, SOLID 원칙에서 O 에 해당하는 Open Closed Principle 을 지키기 위해서 IoC를 한다고 생각할 수 있다.

*Open Closed Principle란 객체 지향의 5대 원칙 중 하나로, 확장에는 열려(Open) 있으나, 변경에는 닫혀(Closed)있어야 한다는 것을 의미한다. (유지 보수를 위해 처음부터 설계를 잘해야 한다는 의미인듯)

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

+ (추가) JWT 사용 흐름 재정리  (0) 2022.12.07
[18] 인증과 인가 (1) 세션/쿠키, JWT  (1) 2022.12.07
[16] IntelliJ 단축키 모음  (0) 2022.12.07
[15] JPA (2) 심화  (0) 2022.12.07
[14] JPA (1)  (0) 2022.12.06

[ IntelliJ 단축키 모음 ]

자동완성 Command + Enter
서드 오버라이 Ctrl + O
인터페이스 구현 Ctrl + I
커서가 가리키는 부분 리팩터링 Ctrl + T
커서가 가리키는 부분을 상수로 빼기 Command + Option + C
이름 일괄 변경(클래스, 변수, 기타 등등) Shift + F6
변수 생성 Command + Option + V
줄 제거 Command + X
해당 코드를 사용중인 코드로 이동 Command + B
구현 코드로 이동 Command + Option + B
코드 위 아래로 이동 Command + Shift + 위/아래
최근 탭으로 이동 Command + E
미리보기와 함께 최근 탭으로 이동 Command + Shift + E
파일 안에서 탐색 Command + F
전체 탐색 Command + Shift + F
파일 안에서 변경 Command + R
전체 변경 Command + Shift + R
대소문자 구분 Option + C
정규식 적용 Option + X
일괄 대/소문자 전환 Command + Shift + U
현재 탭 끄기 Command + W
Import 정리 Ctrl + Option + O
코드(라인) 자동 정렬 Command + Option + L
실행 Option + R
멀티 커서 Option 2번 + 위/아래
테스트 클래스 생성 Command + Shift + T
세미콜론과 함께 자동완성 Command + Shift + Enter
실행 Ctrl + R
디버깅 Ctrl + D
현재 메소드/클래스 실행 Ctrl + Shift + R
현재 메소드/클래스 디버깅 Ctrl + Shift + D
브레이크 포인트 내부 코드로 이동 Command + F7
브레이크 포인트 다음 코드로 이동 Command + F8
다음 브레이크 포인트로 이동 Command + F9
브레이크 포인트 다음 코드로 이동 Command + F8
Run 창으로 이동 Command + 4
Debug 창으로 이동 Command + 5
Service 창으로 이동 Command + 6
Getter, Setter 등 자동 생성 Command + N
한줄 복사 Command + D
한줄 자르기 Command + X
한줄 붙여넣기 Command + V
깃 커밋 Ctrl + K
깃 커밋 후 푸시 Ctrl + Shift + K
VCS 기능 Ctrl + V
현재 열려있는 파일 포커싱
Option + F1 + 1
프로젝트 창 닫기 Shift + ESC
프로젝트 화면에 포커싱 Command + 1
모든 윈도우 창 닫기 Command + Shift + F12
환경설정 창 열기 Command + ,
프로젝트 설정 창 열기 Command + ;
IntelliiJ 전체 검색 창 열기 Shift + Shift
클래스 검색 창 열기 Command + O
파일 검색 창 열기 Command + Shift + O
에러가 발생한 지점으로 이동 F2
인라인으로 코드 수정 Command + Option + N
현재 커서가 있는 부분 선택 Option + 위
Private 메소드 또는 변수 추출 Command + Option + M
클래스 계층 보기 Control + H
메소드 호출 계층 보기 Control + Option + H
전/후 봤던 코드로 이동 Command + Option 좌/우
오버라이딩하는 메소드로 이동 Command + Option + B 
파라미터 미리 보기 Command + P
지역변수를 메소드 파라미터로 추출 Command + Option + P
다음 등장에 대한 멀티 커서 선택 Control + G

 

 

자료 출처

https://mangkyu.tistory.com/139

 

[IDE] 자주 사용되는 인텔리제이(IntelliJ) 단축키 모음(맥북, Mac OS)

1. 자주 사용되는 인텔리제이(IntelliJ) 단축키 모음(맥북, Mac OS) [ IntelliJ 단축키 모음 ] 자동완성 Command + Enter 메서드 오버라이드 Ctrl + O 인터페이스 구현 Ctrl + I 커서가 가리키는 부분 리팩터링 Ctrl

mangkyu.tistory.com

 

영속성 컨텍스트

 

※ 영속성이라는게 뭘까?

  • 오래도록 계속 유지되는 성질.
  • 트랜잭션의 지속성(durability)은 영속성이라고도 하는데 트랜잭션이 성공적으로 완료된 후 데이터베이스에 반영한 수행 결과는 어떠한 경우에도 손실되지 않고 영구적이어야 함을 의미한다. 즉, 시스템에 장애가 발생하더라도 트랜잭션 작업 결과는 없어지지 않고 데이터베이스에 그대로 남아있어야 한다는 의미다.

 

① 영속성 컨텍스트란 ? 

 

출처 자바 ORM 표준 JPA - https://product.kyobobook.co.kr/detail/S000000935744

 

  • 영속성 컨텍스트란 엔티티를 영구 저장 하는 환경 이라는 뜻
  • 어플리케이션(자바 코드 그 자체)이 데이터베이스에서 꺼내온 데이터 객체를 보관하는 역할을 한다.
  • 영속성 컨텍스트는 엔티티 매니저를 통해 엔티티를 조회하거나 저장할때 엔티티를 보관하고 관리한다.
  • 엔티티 매니저마다 개별적으로 부여되는, 어떠한 논리적 공간같은 개념으로 비유적으로 이해할 수 있다.
  • 자바의 엔티티 객체를 엔티티 매니저마다 가지고 있는 영속성 컨텍스트라는 공간에다 넣고 빼고 하면서 사용하는 것
  • “영속화 한다” 라는 말을 “엔티티 매니저가 자기의 영속성 컨텍스트에 넣어준다”로 이해할 수 있다.

 

JPA 엔티티의 상태

 

 

  • 비영속(New) : 영속성 컨택스트와 관계가 없는 새로운 상태. 해당 객체의 데이터가 변경되거나 말거나 실제 DB의 데이터와는 관련없고, 그냥 Java 객체인 상태
// 엔티티를 생성
Member minsook = new Member();
member.setId("minsook");
member.setUsername("민숙");
  • 영속(Managed) : 엔티티 매니저를 통해 엔티티가 영속성 컨텍스트에 저장되어 관리되고 있는 상태. 이와 같은 경우 데이터의 생성, 변경등을 JPA가 추적하면서 필요하면 DB에 반영한다.
// 엔티티 매니저를 통해 영속성 컨텍스트에 엔티티를 저장
em.persist(minsook);
  • 준영속(Detached) : 영속성 컨택스트에서 관리되다가 분리된 상태
// 엔티티를 영속성 컨택스트에서 분리
em.detach(minsook);
// 영속성 컨텍스트를 비우기
em.clear();
// 영속성 컨택스트를 종료
em.close();
  • 삭제(Removed) : 영속성 컨택스트에서 삭제된 상태
em.remove(minsook)

 

영속성 컨텍스트는 어떻게, 왜 이렇게 설계되어있을까?

 

① 1차 캐시라는 것을 가지고 있다.

  • DB를 이용하는 작업은 상대적으로 부하와 비용이 심한 작업이다. 자바 어플리케이션 상에서 데이터를 조회 사용할일이 아주 잦은데, 그럴때마다 DB로 “SELECT * FROM….”과 같은 SQL쿼리를 내는 일은 막아야 한다. 굳이 DB에 접근하지 않아도 요청을 보다 가볍게 처리할 수 있도록 하기위해 영속성 컨텍스트 내부에 1차캐시를 둔다.

 

 

  1. find(”memberB”)와 같은 로직이 있을 때 먼저 1차 캐시를 조회한다.
  2. 있으면 해당 데이터를 반환한다.
  3. 없으면 그 때 실제 DB로 “SELECT * FROM….” 의 쿼리를 내보낸다. (DB접근)
  4. 그리고 반환하기 전에 1차캐시에 저장하고 반환해준다.

 

② “쓰기 지연 SQL 저장소”가 있다.

  • 비슷한 맥락으로 MemberA, MemberB를 생성할 때 마다 DB를 다녀오는건 비효율적이기 때문에, 굳이 여러번 DB를 방문하지 않도록 내부에 “쓰기 지연 SQL 저장소”를 두고 있다.

 

 

  1. memberA, memberB를 영속화 하고
  2. entityManager.commit() 메서드를 호출하면
  3. 내부적으로 쓰기 지연 SQL 저장소에서 Flush가 일어나고
  4. “INSERT A”, “INSERT B”와 같은 쓰기 전용 쿼리들이 DB로 흘러들어간다.

 

③ DirtyChecking을 통해 데이터의 변경을 감지해서 자동으로 수정해준다.

  • JPA는 1차캐시와 쓰기지연 SQL 저장소를 이용해서 변경과 수정을 감지해준다.

 

 

1. 사실 1차 캐시에는 DB의 엔티티의 정보만 저장하는것이 아니다.

2. 해당 엔티티를 조회한 시점의 데이터의 정보를 같이 저장해둔다.

3. 그리고 엔티티객체와 조회 시점의 데이터가 다르다면 변경이 발생했다고 감지한다.

4. 해당 변경 부문을 반영 할 수 있는 UPDATE 쿼리를 작성해둔다.

 

 

④ 데이터의 어플리케이션 단의 동일성을 보장해준다.

  • 값이 같은 데이터가 들어오면 같은 데이터로 취급한다.

 

엔티티 매핑 심화 - 기본 엔티티 매핑 관련

 

@Entity 
@Table (name="USER") 
public class Member { 
	
	@Id 
	@Column (name = "user_id") 
	private String id; 
	 
	private String username; 
	
	private Integer age; 

	@Enumerated (EnumType. STRING) 
	private RoleType userRole;

//	@Enumerated (EnumType. ORDINAL) 
//	private RoleType userRole;

	@Temporal (TemporalType. TIMESTAMP) 
	private Date createdDate;

	@Temporal (TemporalType. TIMESTAMP)  
	private Date modifiedDate;
 
}

@Entity

  1. 기본 생성자는 필수!!
  2. final 클래스, enum, interface 등에는 사용 할 수 없다.
  3. 저장할 필드라면 final을 사용할 수 없다.

@Table

  1. 엔티티와 매핑할 테이블의 이름

@Column

  1. 객체 필드를 테이블 컬럼에 매핑하는데 사용
  2. 생략 가능하다.
  3. 속성들은 자주 쓸 일이 없고, 특정 속성은 무시무시한 effect가 있으니 이름을 지정 할 때 아니고는 보통 생략하기도 한다.

@Enumerated

  1. Java Enum을 테이블에서 사용한다고 생각하면 된다.
  2. 속성으로는 Ordinal, String이 있는데, String인경우 해당 문자열 그대로 저장해서 비용은 많이 들지만, 나중에 Enum이 변경되어도 위험할일이 없기 때문에 일반적으로는 String을 사용한다.

 

연관관계 관련 심화

단방향 연관관계

 

① @ManyToOne

  • 이름 그대로 다대일(N:1) 관계라는 매핑 정보. ( “한명의 유저가 여러개의 주문” )
  • 주요 속성으로는 optional, fetch, cascade가 있다.
  • optional은 말 그대로 false로 설정하면 항상 연관된 엔티티가 있어야 생성할 수 있다는 뜻.

@JoinColumn(name="food_id") 

  • 외래 키를 매핑할 때 사용 (실제 데이터베이스에는 객체필드에는 해당 객체 테이블의 외래키가 들어간다)
  • 기본적으로 @Column이 가지고 있는 필드 매핑관련 옵션 설정들과, 외래키 관련 몇가지 옵션이 추가되어있는 옵션

 

양방향 연관관계

@Getter
@Entity
@NoArgsConstructor
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
		@Column(nullable = false)
    private String memberName;

    @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    public Member(String memberName) {
        this.memberName = memberName;
    }
}
@Getter
@Entity
@NoArgsConstructor
public class Orders {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

    public Orders(Food food, Member member) {
        this.food = food;
        this.member = member;
    }
}
@Getter
@Entity
@NoArgsConstructor
public class Food {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false)
    private String foodName;
    @Column(nullable = false)
    private int price;

    @OneToMany(mappedBy = "food",fetch = FetchType.EAGER)
    private List<Orders> orders = new ArrayList<>();

    public Food(String foodName, int price) {
        this.foodName = foodName;
        this.price = price;
    }
}

 

  • 객체에는 사실 양방향 연관관계라는 것이 없다. 서로 다른 단방향으로 조회하는 로직 2개를 잘 묶어서 양방향인 것처럼 보이게 한 것 뿐
  • 더 정확히는 멤버객체에 주문객체의 주소값을, 주문객체에는 멤버객체의 주소값을 가지고 있는 것
  • 외래키는 연관관계가있는 두개의 테이블 중에서 하나의 테이블에만 있으면 충분하다.
  • 따라서. 이런 차이로 인해 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는데 이것을 연관관계의 주인이라 합니다.
  • 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제) 하게 되어있다.
  • 반면에 주인이 아닌 쪽은 읽기만 할 수 있다. 연관관계의 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것!
  • 연관관계의 주인에 의해 mappedBy 된다.

 

양방향 연관관계의 주의점

  • 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하기. 데이터베이스에 외래 키값이 정상적으로 저장되지 않으면 이것부터 의심해봐야 한다.
  • 해결 : 순수한 객체까지 고려한 양방향 연관관계 - 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전
  • 해결 2 : 연관관계 편의 메소드

 

프록시

  • 엔티티를 조회할 때 연관된 엔티티들이 항상 사용되는 것은 아니다. 연관관계의 엔티티는 비즈니스 로직에 따라 사용될 때도 있지만 그렇지 않을 때도 있다. 실제 사용하다보면 유저의 선택이나, 특정 상황에 따라 연관관계로 맺어진 정보들이 전혀 필요 없을때가 많다.
  • JPA는 굳이 필요없는 DB 조회를 줄이면서 성능을 최적화한다. 이런 문제를 해결하려고 엔티티가 실제 사용될 때까지 데이터베이스 조회를 지연하는 방법을 제공하는데 이것을 지연 로딩이라 한다.
  • 지연 로딩 기능을 사용하려면 실제 엔티티 객체 대상에 데이터베이스 조회를 지연할 수 있는 가짜 객체가 필요한데 이것을 프록시 객체라고 한다.

즉시 로딩 : 엔티티를 조회할 때 연관된 엔티티도 함께 조회 @ManyToOne(fetch = FetchType.EAGER)

지연 로딩 : 연관된 엔티티를 실제 사용할 때 조회, 설정 방법 : @ManyToOne(getch = FetchType.LAZY)

 

@ManyToOne, @OneToOne: 즉시 로딩(FetchType.EAGER)

@OneToMany, @ManyToMany: 지연 로딩(FetchType.LAZY)

 

  • 기본적으로 “즉시로딩”은 연관된 엔티티를 조인해서 다 긁어와버리는 것이고, ”지연로딩”은 실제로 가짜 객체를 이용하면, 그때 별도의 쿼리가 나간다고 생각하면 된다. 
  • 하지만 즉시로딩은, 처음부터 모든 테이블에 조인을 걸어버리고 별도로 쿼리가 나가는 경우가 생기기에, 연관관계가 많고 복잡할수록 비용이 기하급수적으로 늘어나기에, 정확하게 이해하고 필요한 상황이 아니라면, 가급적으로 모두 지연로딩을 걸어두는게 일반적이다.
  • 그렇다면 굳이 필요가 없다면, @ManyToOne(FetchType.Lazy)를 사용하면 된다.

영속성 전이?

  • 특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶으면 영속성 전이기능을 사용하면 된다.
  • JPA는 cascade 옵션으로 영속성 전이를 제공한다
  • 예를들어 유저테이블과 메모 테이블이 있는데, 영속화한 유저객체가 있으면, 메모 테이블도 같이 영속화되어 같이 관리되는 것을 영속성 전이라고 한다.
  • 키워드 : CASCADE
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List<Address> addresses;

 

 

자료 출처 : https://teamsparta.notion.site/JPA-c7d93ee983be486ebee3bcd279e58e48

1. JPA 사용하기 전 문제

어플리케이션이 데이터베이스를 직접 다룰 때 다음과 같은 문제점이 있었다.

  • 훨씬 더 번거롭다.
  • SQL 의존적이라 변경에 취약하다. - ORM 이 없는 환경에서는 백엔드 개발자가 비즈니스 로직 개발보다, SQL 작성에 더 많은 노력을 들여야 했다. SQL 작성이 단순하고 반복적인데, 실수하기 쉽다는 단점도 있었다.
  • 객체지향 모델과 관계형 데이터베이스의 패러다임 불일치가 발생한다. ( 아래 표 참조)

  1. 밀도 문제 : 데이터베이스의 데이터가 더 정형화되어있고 까다롭다.
  2. 관계형 데이터 베이스에는 상속의 개념이 없다. 하지만 상속은 객체의 역할과 구현을 분리해주기 위해 객체 지향 프로그래밍에서 가장 핵심적인 기능 중 하나이다.

이러한 패러다임 불일치에서 기인한 문제들과, 반복적이고 번거로운 어플리케이션 단에서의 쿼리 작업을 줄여주기 위해서 ORM(객체 관계 매핑)기술들이 등장하게 되었다

 

 

2. ORM, JPA 등장

JPA: Java Persistence API 자바 ORM 기술에 대한 표준 명세

 

JPA 역할

  1. 쿼리를 자동으로 만들어 준다.
  2. 어플리케이션 계층에서 sql 의존성을 줄여서 번거로운 작업을 단축시켜 준다.
  3. 패러다임의 불일치를 해결해준다. 
  4. 특정한 상황을 제외하고는,성능도 높여준다. (최적화)
  5. 방언도 지원해준다. h2 Databse를 붙여도, mySql, oracle 뭘 붙여도 코드의 변경이 없다. 관계형 db이자 표준을 준수한 sql을 지원한다면, jpa가 방언들도 알아서 처리해준다.

 

3. DB 의 연관관계 이해

  • 자바는 객체와 레퍼런스로, 데이터베이스는 테이블사이의 관계(FK)로 정보 사이의 연관관계를 표현하고 처리한다
  • 이 두 방식의 차이를 해결해주기 위해서 JPA에는 “Java 어플리케이션 상에서”, “데이터베이스의 연관관계”를 표현해주기 위한 장치들을 가지고 있다.

< DB 의 연관관계 체크사항 >

✔️ JPA 가 제공하는 연관관계는 결국 DB 의 연관관계를 표현하기 위함 

✔️ 따라서 먼저 DB 의 연관관계를 이해해야 한다.

✔️ DB 의 연관관계는 비즈니스 요구사항에 맞춰 이루어진다.

 

 

4. JPA 연관관계

JPA 의 경우는 Enitity 클래스의 필드 위에 연관관계 어노테이션 (@) 을 설정해 주는 것만으로 연관관계가 형성된다.

 

예시

 

 

5. Spring Data JPA 이해

Spring Data JPA 는?

  • JPA 를 편리하게 사용하기 위해, 스프링에서 JPA 를 Wrapping
  • 스프링 개발자들이 JPA 를 사용할 때 필수적으로 생성해야 하나, 예상 가능하고 반복적인 코드들을 Spring Data JPA 가 대신 작성해준다.
  • Repostiory 인터페이스만 작성하면, 필요한 구현은 스프링이 대신 알아서 구현한다.

< Spring Data JPA 추가기능 구현방법 - Spring Data JPA 의 Query Methods >

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods

 

 

6. JPA 영속성 컨텍스트 이해와 1차 캐시 이해

 

'1차 캐시' 사용의 장점

  • DB 조회 횟수를 줄임
  • '1차 캐시'를 사용해 DB row 1개 당 객체 1개가 사용되는 것을 보장 (객체 동일성 보장)

  • 1차 캐시 Entity 객체에만 업데이트 반영됨
  • User DB 에는 반영되지 않음

Entity 업데이트 방법 (1)

  • userRepository.save() 사용

 

Entity 업데이트 방법 (2)

    • @Transactional 을 추가
    • 굳이 userRepository.save() 함수를 호출하지 않아도, 함수가 끝나는 시점에 변경된 부분을 알아서 업데이트 해 줌 (이를 "Dirty check" 라고 함)
    • 간단히 함수가 종료되는 시점에 각 Entity 에 save() 가 호출된다라고 이해
    💡 정확한 이해 위해 필요한 추가학습 내용 : 쓰기 지연 SQL 저장소, flush, commit 등
  •  

 

 

7. (참고) 하이버네이트 (Hibernate)?

  • JPA 는 표준 명세이고, 이를 실제 구현한 프레임워크 중 사실상 표준
  • 스프링 부트에서 기본적으로 "하이버네이트" 사용 중

 

 

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

[16] IntelliJ 단축키 모음  (0) 2022.12.07
[15] JPA (2) 심화  (0) 2022.12.07
[13] @Valid, @Validated (작성중. 수정필요)  (0) 2022.12.06
[12] 정규식(regex, rational expression)  (0) 2022.12.06
[11] Database 와 SQL  (0) 2022.12.06

+ Recent posts