Spring Security

 

Spring 기반 애플리케이션 보안(인증, 권한, 인가 등)을 담당하는 Spring 하위 프레임워크

인증과 권한에 대한 부분을 Filter흐름에 따라 처리

 

Filter는 Dispatcher Servlet 으로 가기 전에 적용 >> 가장 먼저 URL 요청받음

Interceptor는 Dispatcher와 Controller 사이에 위치, 적용 시기가 다름

 

Spring Security는 보안 관련해서 많은 옵션 제공 >> 개발자 입장에서 보안 관련 로직 하나하나 작성하지 않아도 됨

 

 

 

 

Spring Security 아키텍쳐

 

 

동작 방식

 

1. Request 수신

사용자가 Form을 통해 로그인 정보가 담긴 Request 전송

 

2. Token 생성

Authentication Filter가 Request 수신

UserNamePasswordAuthenticationToken (인증용 객체) 생성

UserNamePasswordAuthenticationToken은 해당 요청을 처리할 수 있는 Provider 탐색에 사용

 

3. AuthenticationFilter로부터 인증용 객체 수신

AuthenticationManager에게 처리 위임

AuthenticationManager는 List형태로 Provider 보유

 

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

실제 인증을 할 AuthenticationProvider에게 인증용 객체 전달

 

5. 인증

인증 절차가 시작되면 Authencitation Provider 인터페이스 실행

DB에 있는 사용자 정보와 입력받은 로그인 정보 비교

 

6. UserDetailsService의 loadUserByUsername 메소드 수행

AuthenticationProvider 인터페이스에서 authenticate() 메소드 오버라이딩 

이 메소드의 파라미터로 인증용객체를 활용 >> 로그인 정보를 가져올 수 있음

 

7. DB 사용자 정보 가져오기 위해 UserDetailsService 인터페이스 사용

 

8. UserDetailsService 인터페이스는 입력된 로그인 username정보로 loadUserByUsername() 메소드 호출

DB에 있는 사용자 정보를 UserDetails 객체로 가져옴 (사용자 존재하지 않으면 예외 throw)

DB에서 가져온 사용자 정보와 로그인 정보 비교

일치 시 Authentication 참조 리턴, 일치하지 않으면 예외

 

9. 인증 완료

사용자 정보를 가진 Authentication 객체를 SecurityContextHolder에 저장

성공 시 AuthenticationSuccessHandler 실행

실패 시 AuthenticationFailurHandler 실행

 

 

 

인증(Authorization)과 인가(Authentication)

인증 (Authorization) : 해당 사용자가 본인이 맞는지 확인하는 절차

인가 (Authentication) : 인증된 사용자가 요청한 자원에 접근 가능한지 결정하는 절차

 

 

Spring Security는 기본적으로 인증 절차 거친 후 인가 절차 진행

인가 과정에서 해당 리소스에 대한 접근 권한이 있는지 확인

 

Spring Security에서는 인증, 인가를 위해 Principal을 아이디, Credential을 비밀번호로 사용하는 Crerdential 기반 인증방식 사용

 

Principal : 접근 주체, 보호받는 Resource에 접근하는 대상

Credential : 비밀번호, Resource에 접근하는 대상의 비밀번호

 

 

 

Spring Security 주요 모듈

 

SecurityContextHolder

보안 주체의 세부 정보를 포함

응용프로그램의 현재 보안 컨텍스트에 대한 세부 정보 저장

기본적으로

SecurityContextHolder.MODE_INHERITABLETHREADLOCAL 방법,

SecurityContextHolder.MODE_THREADLOCAL 방법 제공

 

 

SecurityContext

Authentication을 보관하는 역할

SecurityContext 통해 Authentication 객체 활용 가능

 

SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().getAuthentication(authentication);

 

 

Authentication

현재 접근하는 주체의 정보와 권한을 담는 인터페이스

SecurityContext에 저장, SecurityContextHolder를 통해 SecurityContext에 접근

SecurityContext 통해 Authentication에 접근 가능

 

Public interface Authentication extends Principal, Serializable{
	// 현재 사용자의 권한 목록 가져옴
    Collection<? extends GrantedAuthority> getAuthroties();
    
    // credentials (비밀번호)를 가져옴
    Object getCredentials();
    
    Object getDetails();
    
    // Principal 객체 가져옴
    Object getPrincipal();
    
    // 인증 여부
    boolean isAuthenticated();
    
    // 인증 여부 설정
    void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

 

 

UsernamePasswordAuthenticationToken

Authentication을 Implements한 AbstractAuthenticationToken의 하위 클래스

User의 ID가 Principal 역할, Password가 Credential의 역할

첫 번째 생성자는 인증 전의 객체 생성, 두번째는 인증이 완료된 객체 생성

 

public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer{
}

public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {

	private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
    
    // 주로 사용자의 ID에 해당
    private final Object principal;
    
    // 주로 사용자의 Password에 해당
    private Object credentials;
    
    // 인증 완료 전의 객체 생성
    public UsernamePasswordAuthenticationToken(Object principal, Ojbect credentials){
    
    	super(null);
        this.principal = principal;
        this.credentials = credentails;
        setAuthenticated(false);
	}
    
    // 인증 완료 후 객체 생성
    
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection<? extendes GrantedAuthority> authrorities) {
    	
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
      	super.setAuthenticated(true); // super 로 사용해야 됨
	}
}

 

 

 

AuthenticationManager

인증에 대한 부분은 여기서 처리

실질적으로는 AuthenticationManager에 등록 된 AuthenticationProvider에 의해 처리

인증 성공하면 두번째 생성자를 이용해 객체 생성 >> SecurityContext에 저장

 

public interface AuthenticationManager {
	Authentication authentication(Authentication authenticationi) throws AuthenticationException;
}

 

AuthenticationProvider

실제 인증에 대한 부분 처리

인증 전의 Authentication 객체를 받아 인증이 완료된 객체를 리턴하는 역할

아래와 같은 인터페이스를 구현하여 커스텀한 AuthenticationProvider 작성하고 AuthenticationManager에 등록하면 됨

 

public interface AuthenticationProvider {

	Authentication authenticate(Authentication authentication) throws AuthenticationException;
    
    boolean supports(Class<?> authentication);
}

 

 

 

Provider

AuthenticationManager를 Implements한 ProviderManager는 AuthenticationProvider를 구성하는 목록 보유

 

public class ProviderManager implements AuthenticationManager, MessageSoureceAware, InitializingBean {

	public List<AuthenticationProvider> getProviders(){
    	return this.providers;
    }
    
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    
    	Class<? extends Authentication> toTest = authentication.getClass();
        AuthenticationException lastException = null;
        AuthenticationException parentException = null;
        Authentication result = null;
        Authentication parentResult = null;
        int currentPosition = 0;
        int size = this.providers.size();
        
        // for문으로 모든 provider 순회하여 처리하고 result가 나올때까지 반복
        for (AuthenticationProvider provider : getProvider()){ ... }
	}
}

 

 

 

UserDetailsService

UserDetails 객체를 반환하는 하나의 메소드만 보유

일반적으로 이를 Implements한 클래스에 UserRepository를 주입받아 DB와 연결하여 처리

 

public interface UserDetailsService {

	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

 

 

 

UserDetails

인증에 성공하여 생성된 UserDetails 객체는 Authentication 객체를 구현한 UsernamePasswordAuthenticationToken을 생성하기 위해 사용

UserDetails를 Implements하여 처리 가능

 

public interface userDetails extends Serializable {

	// 권한 목록
    Collection<? extends GrantedAuthroty> getAuthorities();
    
    String getPassword();
    
    String getUsername();
    
    // 계정 만료 여부
    boolean isAccountNonExpired();
    
    // 계정 잠김 여부
    boolean isAccountNonLocked();
    
    // 비밀번호 만료 여부
    boolean isCredentialNonExpired();
    
    // 사용자 활성화 여부
    boolean isEnabled();
}

 

 

GrantedAuthority

현재 사용자(Principal)가 가지고 있는 권한을 의미

ROLE_ADMIN, ROLE_USER와 같이 ROLE_?? 형태로 사용

GrantedAuthority 객체는 UserDetailsService에 의해 불러올 수 있고, 특정 자원에 대한 권한이 있는지 검사하여 접근 허용 여부 결정

 

 

'끄적 > BE' 카테고리의 다른 글

TCP UDP  (0) 2023.02.05
Servlet  (0) 2023.01.18
JPA vs MyBatis  (0) 2023.01.11
JPA N+1  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09

TCP, UDP

네트워크 계층들 중, Transport 계층에서 사용되는 프로토콜

Transport 계층:: 송신자, 수신자를 연결하는 통신 서비스를 제공하는 계층

 >> 말 그대로 데이터의 전달을 담당

 

데이터를 전달할 때, 사용되는 프로토콜 >> TCP와 UDP

 

 

TCP

네트워크에서 데이터를 메세지 형태로 보내기 위해 IP와 함께 사용하는 프로토콜

 

일반적으로 TCP, IP를 함꼐 사용

IP는 데이터의 배달

TCP는 패킷 추적 및 관리

 

TCP는 연결형 서비스를 지원하는 프로토콜로, 인터넷 환경에서 기본으로 사용

 

 

특징

- 연결 지향

패킷을 전송하기 위한 논리적 경로 배정

 

- 3-way handshaking

송/수신자 사이에 세션을 수립하는 과정

 

1. 클라이언트는 서버에 연결 요청하는 SYN 패킷 전송 (SYN_SENT 상태)

2. 서버는(Wait for Client 상태) SYN 패킷을 전송 받음 (SYN_RECEIVED 상태)

   SYN+ACK 패킷 보내 응답

3. 서버의 응답받은 클라이언트는 다시 서버에 ACK 패킷으로 응답

서버가 이를 받은 후 세션 생성 (Established) - 연결 완료

 

3단계를 거치면서 클라이언트, 서버 모두 데이터를 전송하고 받을 준비가 되었다는 것을 보장

 

 

- 4-way handshaking 으로 연결 해제

송/수신자 사이의 연결을 해제

 

1. 클라이언트는 연결 종료를 위해 서버에 FIN 플래그 전송 (FIN_WAIT 상태)

2. 서버는 FIN 플래그 받은 후, ACK 패킷 전송, 패킷 전송 이후 데이터를 모두 보낼때 까지 잠시 TIME_OUT

(CLOSE_WAIT 상태)

3. 서버가 연결 종료할 준비가 되면, 연결 해제 준비가 되었다는 FIN플래그를 클라이언트에 전송 (LAST_ACK 상태)

4. 클라이언트는 서버에 ACK로 응답 (FIN_WAIT 에서 TIME_WAIT상태로 변경)

   클라이언트의 ACK를 받은 서버는 연결 해제

   이 때, 클라이언트는 ACK 보낸 이후 일정 시간동안 기다리게 된ㄴ데, 아직 서버에서 받지 못한 데이터가 연결이 해제되어 유실되는 경우를 대비해 잉여 패킷을 기다리는 TIME_WAIT 상태를 일정 기간 유지

   일정 시간이 지나면 연결 종료 후 CLOSE 상태로 변화

 

 

 

- 흐름 제어

송/수신측의 데이터 처리 속도 차이를 해결하기 위한 기법

흐름제어(Flow Control)는 수신자가 패킷을 지나치게 많이 받지 않도록 조절하는 것

기본 개념은 수신자가 송신자에게 현재 자신의 상태를 Feedback 하는 점

 

송신자 속도 > 수신자 속도

데이터를 보내는 속도가 받는 속도보다 빠른 경우 문제 발생

수신자에서 제한된 저장용량 초과한 이후 도착하는 데이터는 손실 가능성 존재

손실된다면 불필요한 응답, 데이터 전송이 빈번하게 발생

이러한 위험을 줄이기 위해 송신자의 데이터 전송량을 수신자에 맞춰 조절

  • Sliding Window ( Go Back N ARQ)

 

 

- 혼잡 제어

혼잡제어는 송신자의 데이터 전달과 네트워크 데이터 처리 속도 차이를 해결하기 위한 기법

 

하나의 라우터에 데이터가 집중될 경우 모두 처리 불가

이 경우 호스트는 재전송을 하게 되고 혼잡을 가중시켜 오버플로우나 데이터 손실을 발생

이를 피하기 위해 송신자가 보내는 데이터의 전송 속도를 강제로 줄이는 작업

 

흐름제어가 송신자, 수신자 사이의 전송 속도를 다루는데 반해, 혼잡제어는 호스트와 라우터를 포함한 보다 넓은 관점에서 전송 문제를 다룸

 

  • AIMD (Additive Increase / Multiplicative Decrease)
  • Slow Start (느린 시작)
  • Fast Retransmit (빠른 재전송)
  • Fast Recovery (빠른 회복)

 

 

- 높은 신뢰성

3-way handshaking, 4-way handshaking 을 통해 신뢰성 있는 연결 구축

 

 

- UDP보다 속도 느림

 

- 전이중(Full-Duplex)

양방향 동시 전송 가능

 

- 점대점(Point to Point) 방식

각 연결이 정확히 2개의 종단점 보유

 

 

UDP

데이터를 데이터그램 단위로 처리하는 프로토콜

 

** 데이터그램

독립적인 관계를 지니는 패킷

 

신뢰성보다는 연속성이 중요한 서비스 (실시간 스트리밍 등)에 사용

 

특징

- 비연결형 서비스 (데이터그램 방식)

 

- 정보를 주고 받을 때, 신호 절차 X

 

- UDP 헤더의 CheckSum 필드를 통해 최소한의 오류 검출

 

- 신뢰성 낮음

연결 설정/해제 과정이 없기 때문

 

- TCP보다 속도 빠름

 혼잡 제어, 흐름 제어와 같은 기능 X

 

 

 

 

 

 

 

TCP Flow

 

UDP Flow

 

'끄적 > BE' 카테고리의 다른 글

Spring Security  (0) 2023.07.18
Servlet  (0) 2023.01.18
JPA vs MyBatis  (0) 2023.01.11
JPA N+1  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09

서블릿?

Dynamic Web Page를 만들 때 사용되는 자바 기반 웹 애플리케이션 프로그래밍 기술

Reqeust, Response를 간단한 메소드 호출로 다룰 수 있게 해주는 기술

 

https://coding-factory.tistory.com/742

서블릿은 자바 기반 컨테이너

 

과정

1. 사용자 URL 입력, HttpRequest 가 서블릿 컨테이너로 전송

2. 요청 받은 서블릿 컨테이너는 HttpRequest를 HttpServletRequest, HttpServletResponse 객체 생성

3. Web.xml 기반으로 사용자가 요청한 URL이 어느 서블릿에 대한 요청인지 탐색

4. 해당 서블릿에서 service() 호출

5. 클라이언트의 Get, Post여부에 따라 doGet(), doPost() 호출

6. doGet(), doPost() 메소드는 동적 페이지를 생성

7. HttpServletResponse객체에 응답을 담아 전송

8. 응답 종료 시 HttpServletRequest, HttpServletResponse 객체 소멸

 

※ web.xml : 서블릿을 작성했다면, 해당 서블릿을 사용자가 요청한 경로와 맵핑시켜야 WAS에서 맵핑된 정보를 읽어서 브라우저에서 해당 URL로 HTTP요청 시 해당 서블릿으로 요청을 전달 가능

톰캣을 예로 들면 웹 어플리케이션 서비스 처리에 대해 정의된 환경 설정 파일이 server디렉터리의 web.xml

 

 

서블릿 예시

public class FirstServlet extends HttpServlet {
	@Override
    public void init() {
    ...
	}
    
    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) {
    ...
    }
    
    @Override
    public void destroy() {
    ...
    }
}

 

특징

- 사용자 Request에 대해 동적으로 작동하는 웹 애플리케이션 컴포넌트

- 기존 정적 웹 프로그램의 문제점을 보완하여 동적인 여러 기능 제공

- Java 스레드 이용하여 동작

- MVC패턴에서 Controller로 동작

- 컨테이너에서 실행

- 쉽게 보안 적용 가능

- javax.servlet.http.HttpServlet 클래스 상속

- UDP보다 속도 느림

- HTML 변경 시 Servlet 재컴파일 필요

 

 

서블릿 생명주기

 

https://coding-factory.tistory.com/742
https://mangkyu.tistory.com/14

 

1. Servlet Request, Servlet Response 객체 생성

2. 설정 파일 참고하여 매핑할 서블릿 확인

3. 해당 서블릿 인스턴스 존재 유무 확인, 없을 경우 init() 메소드 호출하여 생성

4. 서블릿 컨테이너에 스레드 생성하고 service() 실행

5. 응답 처리 후 destroy() 호출하여 Servlet Request, Servlet Response 객체 소멸

(init(), destroy() 메소드는 오버라이딩하여 초기화, 소멸 시의 동작 구현 가능)

 

 

init()

서블릿이 처음 요청 될 때 초기화 하는 메소드

초기화된 서블릿은 싱글톤으로 관리되어 다음에 한번 더 호출 시, 기존에 생성된 서블릿 클래스 호출

 

service()

서블릿 컨테이너가 요청을 받고 응답을 줄때 필요한 메소드

Servlet interfatce를 구현한 HttpServlet 클래스의 doGet(), doPost() 와 같은 메소드 호출

 

destory()

더이상 사용되지 않는 서블릿 클래스는 서블릿 컨테이너가 주기적으로 destory() 메소드 호출하여 제거

제거된 서블릿은 service메소드들에 해당하는 모든 스레드가 종료되거나, 타임아웃 된 경우에는 이 클래스 다시 사용 위해 init() 재필요

 

 

서블릿 설정파일

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">
 
     <servlet> //서블릿 클래스를 서블릿으로 등록
           <servlet-name>myServlet</servlet-name> //해당 서블릿을 참조할 때 사용할 이름
           <servlet-class>controller.MyServlet</servlet-class> //서블릿으로 사용할 서블릿 클래스의 FullName
     </servlet>
 
     <servlet-mapping>
           <servlet-name>myServlet</servlet-name> //매핑할 서블릿의 이름
           <url-pattern>/myServlet</url-pattern> //매핑할 URL 패턴
     </servlet-mapping>
 
</web-app>

서블릿 작성 시, 해당 서블릿을 사용자 요청 경로와 매핑해야 WAS에서 그 정보로 HTTP요청 시 해당 서블릿으로 요청 전달 가능

 

서블릿 컨테이너?

문자 그대로 서블릿을 담고 관리하는 컨테이너

구현되어 있는 서블릿 클래스의 규칙에 맞게 서블릿을 관리

사용자 요청 시 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체 생성

Post, Get 여부에 따라 동적인 페이지 생성하여 응답 리턴

 

HttpServletRequest

Http프로토콜의 Request 정보를 서블릿에게 전달하기 위한 목적으로 사용

Header 정보, 파라미터, 쿠키, URI, URL등의 정보를 읽는 메소드와 Body의 Stream을 읽는 메소드 존재

 

HttpSejrvletResponse

요청을 보낸 사용자에게 응답을 보내기 위한 HttpServletResponse 객체 생성 후 서블릿에 전달

이 객체를 활용하여 Content type, 응답 코드, 응답 메시지 등을 전송

 

 

 

서블릿 컨테이너의 주요 기능

 

1. 생명주기 관리

서블릿의 생명주기 관리

서블릿 컨테이너가 실행되는 순간 서블릿 클래스를 로딩해서 인스턴스화, 초기화 메소드 호출

Request가 오면 적절한 서블릿 메소드를 찾아서 동작

서블릿 생명이 다하는 순간 가비지 컬렉션을 통해 메모리에서 제거

 

2. 통신 지원

사용자의 Request를 받고 Response를 보낼 수 있게 웹 서버와 소켓을 만들어 통신

(소켓 생성, 포트 리스닝, 연결 요청 시 Stream 생성 후 요청 수용 등의 과정을 서블릿 컨테이너가 대신)

listen, accept 등의 기능을 API로 제공하여 복잡한 과정을 생략하고 비즈니스 로직에 집중할 수 있게 해줌

 

3. 멀티스레딩 관리

Rquest를 받고 해당 서블릿의 요청이 들어오면 스레드를 생성해 작업 수행

HTTP service() 메소드 호출, 실행 후 스레드 소멸

동시에 여러 요청이 와도 멀티스레딩 환경으로 동시다발적인 작업 관리 가능

+ 메모리에 올라간 스레드는 다시 생성할 필요 X >> 메모리 관리에 효과적

 

 

 

4. 선언적인 보안관리

서블릿 컨테이너는 보안 관련 기능 지원

개발자는 보안 관련 내용을 서블릿이나 자바 클래스에 구현하지 않아도 됨

일반적으로 XML 배포 서술자에 보안관리를 기록하므로, 보안에 대해 수정할 일이 생겨도 자바코드를 수정하는 일 X

>> 수정마다 재컴파일 불필요

 

 

 

 

 

'끄적 > BE' 카테고리의 다른 글

Spring Security  (0) 2023.07.18
TCP UDP  (0) 2023.02.05
JPA vs MyBatis  (0) 2023.01.11
JPA N+1  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09

JPA

ORM 표준 명세

객체와 DB테이블을 매핑하여 데이터를 객체화

- 개발자가 반복적인 SQL 작성 X

- DBMS 종속 X

- 복잡한 쿼리는 jpql 사용하거나 SQL Mapper 혼용 가능

 

JPA

** spring data jpa 에 관한 설명은 아래 링크 ** https://rainover0824.tistory.com/38 JPA, Spring Data Jpa JPA 핵심 : Persistence 클래스 EntityManager에서 제공하는 API 사용 ex) @Repository @RequiredArgsConstructor public class OrderRepo

rainover0824.tistory.com

 

 

MyBatis

자바에서 SQL Mapper를 지원해주는 프레임워크

SQL Mapper

 SQL을 직접 작성하고 쿼리 수행 결과를 어떤 객체에 매핑할지 바인딩하는 방법 (DBMS 종속적)

SQL 쿼리를 사용하여 DB에 접근, 데이터를 객체화

SQL 쿼리를 직접 작성하여 쿼리 수행결과를 객체와 매핑

 

 

장점

쿼리를 XML로 분리 가능

복잡한 쿼리 작성 가능

최적화된 쿼리 구현 가능

데이터 캐싱 기능으로 성능 향상

Entity에 종속받지 않고 다양한 테이블 조합 가능

 

단점

스키마 변경 시 SQL쿼리 직접 수정 필요

반복되는 쿼리가 발생

런타임시에 오류 발생 >> 디버깅에 어려움

DB변경시 관련 로직도 모두 수정 필요

'끄적 > BE' 카테고리의 다른 글

TCP UDP  (0) 2023.02.05
Servlet  (0) 2023.01.18
JPA N+1  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09
REST API  (0) 2023.01.09

N+1 문제란?

의도치 않게 여러개의 Select문이 짧은 시간내에 실행되는 현상

연관관계가 설정된 Entity를 조회할 경우에 조회한 데이터 개수(N)만큼 연관관계의 조회 쿼리가 추가로 발생하는 현상

 

 

예시

출처 : https://programmer93.tistory.com/83

FetchType.EAGER

TEAM과 USER 테이블이 위와 같이 1:N 관계를 가질 때

 

@Entity
public class User {
    @Id
    @GeneratedValue
    private long id;
    private String firstName;
    private String lastName;

    @ManyToOne(fetch = FetchType.EAGER)		// 즉시 로딩
    @JoinColumn(name = "team_id", nullable = false)
    private Team team;
}
@Entity
public class Team {
    @Id
    @GeneratedValue
    private long id;
    private String name;

    @OneToMany(fetch = FetchType.EAGER)
    private List<User> users = new ArrayList<>();
}

@ManyToOne 어노테이션을 활용하여 연관관계 매핑 시, fetch 속성을 FetchType.EAGER (즉시 로딩)으로 설정한 경우

JpaRepository에서 findAll 호출하게 되면

 

Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?

위와 같이 TEAM을 전체 조회하는 쿼리가 발생하고 그 TEAM에 속한 USER를 조회하는 쿼리들이 파생되어 발생

TEAM이 여러개가 된다면?  조회되는 모든 TEAM에 대해 연관된 USER를 하나하나 조회하는 쿼리가 발생

불필요한 쿼리 증가

 

 

FetchType.LAZY

FetchType.EAGER를 FetchType.LAZY로 변경하게 되면

Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_

N+1 문제가 발생하지 않는 점 확인 가능

 

But

Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?
Hibernate: select users0_.team_id as team_id1_1_0_, users0_.users_id as users_id2_1_0_, user1_.id as id1_2_1_, user1_.first_name as first_na2_2_1_, user1_.last_name as last_nam3_2_1_, user1_.team_id as team_id4_2_1_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id=?

USER를 탐색할 때 N+1문제가 발생

EAGER와 LAZY는 N+1문제가 발생되는 시점만 다름

 

 

 

Why?

 

우선 FetcyType.EAGER 일 때의 동작 과정을 살펴보면

 

1. findAll() 호출 시

select t from Team t 라는 jpql 실행, 해당 구문을 분석한 select * from team 이라는 SQL 생성되어 실행

(Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_)

2. DB의 결과를 받아 team의 Entity 인스턴스 생성

3. team과 연결되어 있는 user도 로딩 필요 >> 영속성 컨텍스트에서 연관된 user가 존재하는 확인

4. 없다면 2에서 만들어진 인스턴스 개수에 맞게 select * from user where team_id=? 라는 SQL생성 후 실행

 

FetchType.LAZY 라면

3, 4번 과정이 전체 객체 조회 시 발생하는 것이 아닌 user 객체를 사용하는 시점에서 발생

** user 객체를 활용하고 싶다 >> user도 로딩이 필요 >> 3, 4번 과정 반복 **

 

 

해결 방법

 

Fetch Join

jpql을 사용해 DB에서 데이터를 가져올 때 처음부터 연관된 데이터까지 함께 가져오는 방법

(SQL의 Join구문)

 

@Query 어노테이션을 활용하여 직접 jpql 작성 필요

    @Query("select t from Team t join fetch t.users")

 

findAll() 호출 시

Hibernate: select team0_.id as id1_0_0_, user2_.id as id1_2_1_, team0_.name as name2_0_0_, user2_.first_name as first_na2_2_1_, user2_.last_name as last_nam3_2_1_, user2_.team_id as team_id4_2_1_, users1_.team_id as team_id1_1_0__, users1_.users_id as users_id2_1_0__ from team team0_ inner join team_users users1_ on team0_.id=users1_.team_id inner join user user2_ on users1_.users_id=user2_.id

jpql에서 join fetch 구문은 Inner Join 구문으로 변경되어 실행

 

 

EntityGraph

Fetch Join을 jpql이 아닌 어노테이션으로 활용하는 방법

 

      @Override
      @EntityGraph(attributePaths = {"team"})
      List<Member> findAll();

findAll() 메소드를 Ovveride 하고 @EntityGraph 어노테이션의 attributePaths 속성의 값을 join하고 싶은 객체로 설정

 

Fetch Join의 경우 따로 Outer Join을 명시하지 않으면 Inner Join 실행

EntityGraph의 경우 기본적으로 Left Outer Join 실행

아우터 조인이기 때문에 필요 이상의 컬럼이 조회될 가능성 존재

 

 

Batch Size

N+1 문제가 발생했을 경우에 select * from user where team_id in(?, ?, ?) 방식으로 N+1 문제가 발생하는 바법

 

application.yml 설정

spring:
  jpa:
    properties:
      hibernate:
        default_batch_fetch_size: 1000

 

application.properties 설정

spring.jpa.properties.hibernate.default_batch_fetch_size=1000

 

Entity 설정

@OneToMany(fetch = FetchType.EAGER)
@BatchSize(size = 1000)

 

원하는 방법대로 골라서 설정하면 

Hibernate: select team0_.id as id1_0_, team0_.name as name2_0_ from team team0_
Hibernate: select users0_.team_id as team_id1_1_1_, users0_.users_id as users_id2_1_1_, user1_.id as id1_2_0_, user1_.first_name as first_na2_2_0_, user1_.last_name as last_nam3_2_0_, user1_.team_id as team_id4_2_0_ from team_users users0_ inner join user user1_ on users0_.users_id=user1_.id where users0_.team_id in (?, ?, ?, ?)

위와 같이 in 을 사용한 쿼리 발생

 

 

 

실무에서?

우선 연관관계애 대한 설정이 필요하다면 FetchType을 LAZY로 사용하고 최적화 필요한 부분에 대해서 Fetch Join 사용

기본적인 Batch Size의 값을 1000 이하로 설정 (대부분 DB에서 In절의 최대 개수가 1000개이기 때문)

 

'끄적 > BE' 카테고리의 다른 글

Servlet  (0) 2023.01.18
JPA vs MyBatis  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09
REST API  (0) 2023.01.09
HTTP  (0) 2023.01.09

Spring?

Java기반 웹 프레임워크

현대 Java기반 엔터프라이즈 어플리케이션을 위한 프로그래밍 및 Configuration Model 제공

 

 

Framework?

프레임워크는 어떤 목적을 쉽게 달성하기 위한 도구의 역할

자주 쓰일만한 기능을 모아놓은 유틸(클래스) 모음

기본 설계, 라이브러리는 프레임워크에서 제공하니, 개발자는 개발에 집중 가능

 

라이브러리 + 설계도 의 개념

 

 

Spring 특징

  • Java 객체와 라이브러리 관리
  • 경량 컨테이너로 Java 객체를 직접 관리 (Spring Container, Bean)
  • 객체의 생성, 소멸과 같은 생명주기를 관리
  • Inversion of Control (제어 반전)
 

Inversion of Control (제어 반전)

IoC? 객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀐다는 뜻 개발자 >> Spring 으로 역전 컴포넌트 의존관계 설정, 설정, 생명주기를 해결하기 위한 디자인 패턴 IoC Container Spring

rainover0824.tistory.com

 

Dependency Injection (의존성 주입)

Dependency (의존) ? A가 B에 의존하고 있는 상태일 때, B에 변화가 일어나면 그 변화가 A에도 영향을 미치는 것 class Chef { private Recipe recipe = new Recipe(); public Chef() { this.recipe.cook(); } } 흔히 드는 예시 중

rainover0824.tistory.com

 

 

Spring Boot 

Spring을 더 쉽게 사용하기 위한 도구

 

 

기존의 Spring에서는 개발자가 다양한 설정을 직접 해줘야 하는데, 이 점을 간소화

 

 

1. Dependency

Spring의 경우 Dependency 설정이 복잡하고 버전 관리도 직접 수행

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.5</version>
</dependency>

 

 

Spring Boot의 경우 Dependency를 보다 쉽게 설정 가능

버전 관리도 알아서 수행

implementation 'org.springframework.boot:spring-boot-starter-web'

 

!! 쉽게 한 줄로 Dependency 추가 및 자동 버전관리가 가능 !!

 

 

2. Configuration

 

Spring의 경우 Configuration 설정 복잡

 

Ex)

Thymeleaf를 사용하고자 할 때

 

@Configuration
@EnableWebMvc
public class MvcWebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = 
          new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);
        return templateEngine;
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);
    }
}

 

Spring 에서는 이렇게 긴 Configuration 클래스를 만들어야 하지만

Spring boot에서는 별도의 Configuration이 필요 없이

 

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf

Dependency만을 추가하는 것으로 Thymeleaf 사용 가능

 

AutoConfiguration

추가한 jar파일에 따라 자동적으로 설정 수행

Ex)

HSQLDB가 클래스 패스에 존재하고 DB커넥션을 맺는 Bean을 수동으로 구성하지 않았다면, 자동으로 인메모리 DB로 구성

>> Spring Legacy였다면 Connection Error 리턴해서 어플리케이션 실행 자체가 불가

 

 

 

@SpringBootApplication 어노테이션을 사용해서 AutoConfiguration 사용 가능

아래 3가지의 기능 포함

 

  • @EnableAutoConfiguration

클래스패스에 있는 /resource/META-INF/spring.factories 중 EnableAutoConfiguration 부분에 정의된 Configuration들을 자동 등록

>> AutoConfiguration의 등록 조건을 만족하는 경우에만

 

  • @ComponentScan

base-package가 정의되지 않으면 해당 어노테이션이 붙은 클래스패스 하위의 @Component 어노테이션을 스캔하여 Bean으로 등록

 

  • @SpringConfiguration

@Configuration과 같은 기능

 

 

 

3. 편리한 배포

Spring Legacy의 경우 war파일을 Web Application Server에 담아 배포

Spring Boot의 경우 Tomcat, Jetty와 같은 내장 WAS를 가지고 있기 때문에 jar파일로 간편하게 배포 가능

 

'끄적 > BE' 카테고리의 다른 글

JPA vs MyBatis  (0) 2023.01.11
JPA N+1  (0) 2023.01.11
REST API  (0) 2023.01.09
HTTP  (0) 2023.01.09
MVC1 MVC2  (0) 2023.01.05

REST?

Representational State Transfer

자원의 이름으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미

프로토콜이나 표준이 아닌 아키텍쳐 제약 조건

SW의 아키텍쳐를 어떻게 형성할 지에 대한 가이드라인

 

 

 

API?

Application Programming Interface

응용프로그램에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스

프로그램들이 서로 상호작용하는 것을 도와주는 매개체로 볼 수 있음

 

https://www.redhat.com/ko/topics/api/what-are-application-programming-interfaces

 

 

 

REST API, RESTful API

Web에서 활용하게 되는 API가 REST가이드라인을 따른다면 RESTful API

6개의 가이드라인을 전부 따르지 않아도 어느정도 REST 제약을 지킨다면 REST API

 

REST API?

REST 기반으로 서비스 API를 구현한 것

 

  • 사내 시스템을 REST기반으로 분산해 확장성, 재사용성을 높여 유지보수, 운영 편리성을 높일 수 있음
  • HTTP표준 기반으로 구현하기 때문에 HTTP를 지원하는 언어로 클라이언트, 서버 구현 가능
  • 즉, REST API제작하면 Delphi, Java, C# 등을 이용해 클라이언트를 제작 할 수도 있음

 

REST 가이드라인

1. Uniform Interface

URL만 보고 어떤 정보가 들어올지 예측 가능하도록 하나의 URL로는 한 개의 데이터만 가져와야 함

ex) instagram.com/username/photos

 >> 특정 회원의 인스타그램 사진첩임을 유추 가능

 

전체적인 시스템 아키텍처를 간단하고 잘 파악할 수 있도록 약속된 Interface

클라이언트 개발자와 서버 개발자 사이의 결합도를 낮춤

 

Uniform Interface 제약 조건

  •  Identification of resources

리소스가 URI로 식별

 

  • Manimpulation of resources through representations

Represestation 전송을 통해 리소스를 조작 가능

>> 리소스 CRUD 할 때에도 메소드를 저장하는 것을 의미

 

  • Self-Descriptive messages

자기서술적 메시지

메시지만으로 어떤 메시지인지 알 수있어야 함

 

self-descriptive message의 예시

 

Request

Get / HTTP/1.1
Host: www.example.org

Response

HTTP/1.1 200 OK
Content-Type: application/json-patch+json
\[{ “op” : “remove”, “path” : “a/b/c"}\]

 

 

  • Hypermedia as engine of application state (HATEOAS)

Hypermedia로 어플리케이션 상태 설명

 

HTTP/1.1 200 OK
Content-Type: application/json
Link: </articles/1>; rel=“previous”,
      </articles/3>; rel=“next”;
{
    “Title” : “The second article”,
    “content” : “Hello! Brother"
}

이렇게 표현해도 되고

 

HTTP/1.1 200 OK
Content-Type: application/json
{
    “Title” : “The second article”,
    “content” : “Hello! Brother"
    href :
    {
        previous : /article/1
        next : article/3
    }
}

Json에 포함시켜도 됨

 

 

 

2. Client-Server 역할 구분

클라이언트 : Request

서버 : Response

 

사용자들에게 제공하는 Interface인 User Interface와 Data Storage, 알고리즘 등 서버 내부의 작업을 분리

>> User Interface는 여러 플랫폼에서 이식성 향상을 기대

>> 서버 구성요소 단순화하여 확장성 기대

 

클라이언트는 서버의 리소스 URI만 알면 되기 때문에 클라이언트와 서버가 서로 의존하지 않고 별도로 진화 가능

 

 

3. Stateless

각 요청은 독립적으로 처리

요청들 사이에 의존성이 존재 X

 

클라이언트에서 서버로의 Request에는 그 요청을 이해하기 위한 정보가 포함되어야 함

세션의 정보는 전적으로 클라이언트가 보유

 

Ex)

로그인 세션 유지가 필요하다면 그 정보 또한 클라이언트가 가지고 서버에 전달

대표적으로 JWT토큰 등을 사용

 

 

4. Cacheable

요청에 대한 응답 내의 데이터에 캐시 가능 여부를 명시해야 함

응답을 캐시할 수 있다면 동일한 Request시에 응답 데이터 재사용 가능해야 함

 

Cache-Control 헤더를 통해 캐시 여부 명시

 

 

5. Layered System

요청 처리, DB 저장 등 여러 단계를 거쳐 요청을 처리

계층화된 시스템 아키텍처를 사용하여 각 구성원들 사이의 계층간 상호작용 제한

>> Interface 일원화

 

 

6. Code on demand(Optional)

서버가 네트워크를 통해 클라이언트에 전달한 Javascript 등과 같은 프로그램들은 그 자체로 실행이 가능해야 함

>> 사전 구현에 필요한 기능을 간소화하여 클라이언트 단순화

 

바로 실행 가능한 코드를 클라이언트에 보내서 실행

 

 

 

REST 구성요소

1. Resource

자원(URI)

모든 자원에 고유한 ID존재, 이 자원은 서버에 존재

자원을 구별하는 ID는 HTTP URI (/groups/:group_id)

클라이언트는 URI를 통해 자원을 지정, 해당 자원의 상태(정보)에 대한 조작을 서버에 요청

 

 

2. Verb

행위

HTTP 메소드

HTTP프로토콜 메소드 사용

HTTP프로토콜은 GET, POST, PUT, DELETE등의 메소드 제공

 

3. Representation of Resource

표현

클라이언트가 자원의 상태(정보)에 대한 조작을 요청하면 서버는 이에 적절한 응답 전송

REST에서 하나의 자원은 JSON, XML, TEXT, RSS등 여러 형태 가능

보통 Json, XML 사용

 

'끄적 > BE' 카테고리의 다른 글

JPA N+1  (0) 2023.01.11
Spring / Spring Boot  (0) 2023.01.09
HTTP  (0) 2023.01.09
MVC1 MVC2  (0) 2023.01.05
Inversion of Control (제어 반전)  (0) 2023.01.03

HTTP?

Hypertext Transfer Protocol

하이퍼텍스트 전달하는 프로토콜

HTML과 같은 리소스를 가져올 수 있도록 해주는 프로토콜

 

웹에서 이루어지는 모든 데이터 교환의 기초

클라이언트-서버 프로토콜

 

https://developer.mozilla.org/ko/docs/Web/HTTP/Overview

 

클라이언트와 서버들은 개별적인 메시지 교환에 의해 통신

클라이언트가 보내는 메시지 :: Request

서버의 응답 메시지 :: Response

 

 

https://developer.mozilla.org/ko/docs/Web/HTTP/Overview

어플리케이션 계층 프로토콜

신뢰 가능한 전송 프로토콜이라면 이론상 무엇이든 사용 가능

보통은 TCP, TLS(암호화된 TCP)를 통해 전송

 

확장성 덕분에 하이퍼텍스트 문서 뿐만 아니라 이미지, 비디오, HTML폼 결과를 서버로 POST하기 위해서 사용하기도 함

.

클라이언트의 개별적인 요청들은 서버로 전송

서버는 요청을 처리하고 Response라는 응답 전송

Request와 Response사이에는 여러 개체가 존재 (Proxy같은)

 

 

HTTP 작동방식

클라이언트

서버에게 요청을 보내는 리소스 사용자

웹 브라우저, 모바일 어플리케이션, IoT 등

 

서버

클라이언트에게 요청에 대한 응답을 제공하는 리소스 관리자

 

 

Proxy

웹 브라우저와 서버 사이에는 수많은 컴퓨터와 머신이 HTTP메시지를 이어받고 전달

이러한 컴퓨터, 머신들 중 어플리케이션 계층에서 동작하는 것들을 일반적으로 Proxy라고 호칭

 

  • 캐싱 (브라우저 캐시 등)
  • 필터링 (바이러스 백신 스캔, 유해 컨텐츠 차단 등)
  • 로드 밸런싱 (여러 서버들이 서로 다른 요청을 처리하도록 허용)
  • 인증 (다양한 리소스에 대한 접근 제어)
  • 로깅 (이력 정보 저장)

 

 

HTTP 메시지

Request

요청 메시지

Method : HTTP 요청 메소드 (GET, POST 등)

Path : 가져오려는 요청 메시지의 경로

           (프로토콜 http://, 도메인 developer.mozilla.org, TCP포트 80) 등을 제거한 리소스 URL

Version of the protocol : 프로토콜의 버전 (HTTP/1.1)

Headers : 서버에 대한 추가 정보를 전달 (리소스 요청 경로 등)

 

Response

응답 메시지

Version of the protocol : 프로토콜 버전 (HTTP/1.1)

Status Code : 요청의 성공 여부, 그 이유를 나타내는 상태 코드 (200 성공)

Status Message : 상태코드의 짧은 설명

Header : Request 메시지의 헤더와 마찬가지로 메시지에 대한 정보

 

 

 

 

HTTP 메소드

  • GET : 서버로부터 데이터 취득
  • POST : 서버에 데이터를 추가, 작성
  • PUT : 서버의 데이터 갱신 (전체 갱신)
  • PATCH : 리소스의 데이터 갱신 (일부분 갱신)
  • DELETE : 서버의 데이터 삭제
  • HEAD : 서버 리소스의 헤더 (메타 데이터 취득)
  • OPTIONS : 리소스가 지원하고 있는 메소드의 취득
  • CONNECT : Proxy 동작의 터널 접속 변경

 

 

GET

주로 데이터를 읽거나(Read) 검색(Retrieve)할때 사용되는 메소드

GET요청이 성공적으로 이루어진다면 XML이나 JSON과 함께 200(OK) HTTP응답 코드 리턴

에러 발생시 에러 코드 리턴 (404, 400, 500 등)

 

- HTTP 명세에 의하면 GET은 오로지 데이터를 읽을때만 사용

- 멱등성 O 

- 데이터를 변경하는 연산에 사용 X

 

 

** 멱등성?

Idempotence

여러번 수행해도 같은 결과를 반환하는 것

호출로 인해 데이터가 변형되지 않는다는 것을 의미

 

Ex)

GET / User/1

조회이기 때문에 요청 시, Body와 Content-Type이 비워져 있음

조회할 데이터에 대한 정보는 URL을 통해 파라메터를 전달

조회 성공 시 Body값에 데이터 값을 저장하여 성공 응답 리턴

 

!! GET은 캐싱이 가능하여 같은 데이터를 여러 번 조회할 경우 저장한 값을 사용하여 조회 속도 향상 !!

 

 

POST

새로운 리소스를 생성(Create)할때 사용

정확히는 하위 리소스(부모 리소스의 하위 리소스)들을 생성하는데 사용

성공적으로 생성되면 201 (Created) HTTP 응답 리턴

 

- 멱등성X

- 같은 요청 반복했을 때, 항상 같은 결과물이 나오지 않기 때문

- 같은 POST 두번 보내면 같은 정보를 담은 두개의 다른 Resource를 반환할 가능성 높음

 

Ex)

POST /user
body : {date : "example"}
Content-Type : "application/json"

데이터 생성을 위해 Body, Content-Type 지정 필요

URL이 아닌 Body를 통해 값 전달받음

데이터 조회 성공 시 Body 값에 저장된 데이터 값을 저장하고 성공 응답 리턴

 

 

PUT

리소스 생성/업데이트를 위해 사용

 

- 멱등성 O

- 동일한 PUT요청 여러번 하면 항상 동일한 결과 생성

 

Ex)

PUT /user/1
body : {date : "update example"}
Content-Type : "application/json"

 데이터 수정 위해 Body, Content-Type 필요

URL을 통해 수정할 데이터를 조회하기 위한 Parameter 전송

Body에 수정할 데이터 값 담아 전송

데이터 조회 성공 시 Body 값에 저장된 데이터 값을 수정하여 성공 응답 리턴

 

 

PATCH

PUT과 마찬가지로 리소스를 수정할때 사용

 

- PUT과 달리 데이터의 일부분만 수정

- 멱등성 X

 

Ex)

PATCH /user/1
body : {date : "update example"}
Content-Type : "application/json"

 데이터 수정 위해 Body, Content-Type 필요

URL을 통해 수정할 데이터를 조회하기 위한 Parameter 전송

Body에 수정할 데이터 값 담아 전송

데이터 조회 성공 시 Body 값에 저장된 데이터 값을 수정하여 성공 응답 리턴

 

DELETE

리소스 삭제를 위해 사용

 

Ex)

DELETE /user/1

조회와 마찬가지로 Body, Content-Type 불필요 (삭제만 하기 때문)

URL통해 삭제할 데이터를 조회하기 위한 Parameter 전송

데이터 삭제 성공 시 Body값 없이 성공 응답만 리턴

 

 

 

기타

 

URL에 데이터 정보가 없기 때문에  POST 방식이 GET보다 보안 관점에서 좋음

 

POST와 PUT은 구분해서 사용

POST는 새로운 데이터를 계속해서 생성하지만, PUT은 같은 요청 계속하더라도 데이터가 계속 생성되지 않음

 

 

 

'끄적 > BE' 카테고리의 다른 글

Spring / Spring Boot  (0) 2023.01.09
REST API  (0) 2023.01.09
MVC1 MVC2  (0) 2023.01.05
Inversion of Control (제어 반전)  (0) 2023.01.03
Dependency Injection (의존성 주입)  (0) 2023.01.03

 

MVC1

View, Controller를 모두 JSP가 담당하는 형태

JSP에 HTML, CSS등의 코드가 뒤섞여 가독성 저해

 

 

JSP 하나로 Request, Response 모두 처리하기 때문에 구현 난이도 쉬움

재사용성, 가독성 별로

>> 복잡한 프로젝트일수록 유지보수에 있어서 좋지 않은 패턴

 

 

MVC2

View와 Controller 분리

흔히 사용하는 MVC패턴

 

Model, View, Controller 에서 수정 필요한 부분만 수정 가능

>> 유지보수성 좋음

 

MVC2패턴 개발 보조를 위한다양한 Framework 존재

대표적으로 Spring MVC

'끄적 > BE' 카테고리의 다른 글

REST API  (0) 2023.01.09
HTTP  (0) 2023.01.09
Inversion of Control (제어 반전)  (0) 2023.01.03
Dependency Injection (의존성 주입)  (0) 2023.01.03
Persistence Context (영속성 컨텍스트)  (0) 2023.01.01

IoC?

객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀐다는 뜻

개발자 >> Spring 으로 역전

 

컴포넌트 의존관계 설정, 설정, 생명주기를 해결하기 위한 디자인 패턴

 

 

IoC Container

Spring에서 객체의 생성과 관리, 의존성의 관리를 수행하는 컨테이너

 

인스턴스 생성부터 소멸까지 인스턴스 생명주기 관리를 개발자가 아닌 컨테이너가 대신해줌

객체관리 주체가 개발자가 아닌 컨테이너가 되기 때문에(역전) 개발자는 로직에 집중 가능

  • 객체의 생성을 책임지고 의존성을 관리
  • POJO의 생성, 초기화, 서비스, 소멸에 대한 권한 보유
  • 개발자들이 직접 POJO(Plain Old Java Object)를 생성할 수도 있음
  • 개발자는 비즈니스 로직에 집중 가능
  • 객체 생성 코드가 없으므로 TDD(테스트 주도 개발) 용이

Spring이 직접 만들고 관계를 부여하는 오브젝트 :: Bean

Bean의 생성과 결정과 같은 IoC 오브젝트 :: Bean Factory

 

 

BeanFactory

컨테이너에서 객체 생성, DI처리하는 기능만 제공

Bean 등록, 생성, 조회, 반환 관리

Bean조회할 수 있는 getBean() 메소드 정의

보통은 BeanFactory 바로 사용하지 않고 이를 확장한 ApplicationContext 사용

 

 

ApplicationContext

Bean을 등록, 생성, 조회, 반환 관리하는 기능

여기에 더해 Spring의 각종 부가기능 추가제공

 

  • 국제화가 지원되는 텍스트 메세지 관리
  • 이미지같은 파일 자원 로드할 수 있는 포괄적인 방법 제공
  • 리스너로 등록된 빈에게 이벤트 발생을 알려줌

출처 :&nbsp;https://dog-developers.tistory.com/12

 

 

public class UserDao {

  private DConnectionMaker dConnectionMaker;

  public UserDao(DConnectionMaker dConnectionMaker) {
    this.dConnectionMaker = dConnectionMaker;
  }
}

IoC 미적용

 

public class UserDao {

  private DConnectionMaker dConnectionMaker;

  public UserDao(DConnectionMaker dConnectionMaker) {
    this.dConnectionMaker = dConnectionMaker;
  }
}

@Configuration
public class DaoConfig {

  @Bean
  public DConnectionMaker dConnectionMaker() {
    return new DConnectionMaker();
  }

  @Bean
  public UserDao userDao() {
    return new UserDao(dConnectionMaker());
  }
}

IoC 적용

@Configuration :: ApplicationContext가 활용하는 IoC설정 정보

ApplicationContext는 DaoConfig 클래스를 설정 정보로 등록, @Bean이 붙은 메소드의 이름을 가져와 Bean 목록 생성

 

 

 

'끄적 > BE' 카테고리의 다른 글

HTTP  (0) 2023.01.09
MVC1 MVC2  (0) 2023.01.05
Dependency Injection (의존성 주입)  (0) 2023.01.03
Persistence Context (영속성 컨텍스트)  (0) 2023.01.01
Spring MVC  (0) 2022.12.29

+ Recent posts