Spring 입문 강의 정리

김건우·2023년 12월 18일

개발 공부

목록 보기
7/13
post-thumbnail

Spring 전반

Spring은 JAVA / Kotlin 기반의 Application Framework 이다.

Framework과 Library의 정의

  • Framework
    • Application을 개발하기 위한 규약과 다양한 요소들을 제공하는 틀
  • Library
    • Application 개발시 활용가능한 도구(코드)의 집합

Module, Package, library

  • Package, Module, Library 순으로 사이즈가 점점 더 커진다고 볼 수 있다.
  • Package
    • Package는 관련 클래스 및 인터페이스 집합을 구성하는 네임스페이스dl다. Java, Kotlin에서는 개념적으로 하나의 디렉토리라고 볼 수 있다.
  • Module
    • Module은 패키지와 관련 리소스의 모음이다. 하나의 작은 역할을 담당한다.
    • Java Module 은 Application 혹은 API 를 별도의 module로써 패키징하는 매커니즘이다.
  • Library
    • Library는 기능의 집합이라 할 수 있다.
    • 여러 개의 모듈로 구성된다.
    • 예를 들어, Collections 라이브러리는 Set module, List module, Map module 등으로 구성된다고 말할 수 있다.

Spring 의 용도

  • 이전에는 HTML / CSS와 같은 리소스를 응답해주는 역할도 했지만, 현재에는 Data를 주로 응답해주는 역할을 한다. 여기서 Data는 여러 형태가 될 수 있지만, 현재에는 대부분 JSON 포맷을 사용한다.
  • JSON은 아래 예시처럼 key, value 형태로 이루어진 포맷이라 할 수 있고, Key는 문자열(String), Value로는 수(Number), 문자열(String), 참/거짓(Boolean), 배열 (Array), 객체 (Object), null 값이 올 수 있다.
  • 현재의 Spring은 Client, Frontend Server의 요청에 따라 적절한 JSON Data를 응답해주는 역할을 주로 한다고 볼 수 있다.

Spring vs Spring Boot - Plumbing의 차이

  • Plumbing : Application의 각 요소들을 조합하는 과정이다.
  • 원래 개발자들이 코드를 통해 요소 A 다음에 요소 B, 요소 C 를 연결하는 과정을 직접 해줘야 했지만, Spring Boot는 Spring이 자동으로 이러한 과정을 할 수 있도록 도와주는 도구다.

Spring 구조와 주요 기술

Web Application을 만들기 위해 필요한 요구사항

  • 유저 혹은 Frontend Application의 요청을 처리하고, 적절한 응답을 줄 수 있어야 한다.
  • 예외 처리를 할 수 있고, 예외가 발생했을 때 적절한 응답을 줄 수 있어야 한다.
  • 인증과 인가 처리를 할 수 있어야 한다. (Authentication, Authorization)
  • 비즈니스 로직을 처리할 수 있어야 한다.
  • Transaction 관리 전략이 있어야 한다. ( 데이터 처리 단위 )
  • 스토리지 및 다른 외부 시스템과 통신할 수 있어야 한다.

Spring의 Layer 구조

  • 관심사의 분리를 통해 코드의 재사용성, 유지보수성 향상
  • Web Layer
    • Application의 최상위 Layer이다.
    • Client의 요청을 받고, 응답을 주는 역할을 주로 한다. (Controllers)
    • 하위 Layer에서 발생한 예외들을 처리하여 적절한 응답을 준다. (Exception Handlers)
    • 인증과 인가 처리를 담당한다. (Filters)
  • Service Layer
    • Web Layer 하위에 존재하는 Layer이다.
    • Transaction 경계의 역할을 한다.
    • Application Service, Infrastructure Service로 나뉘어진다.
      • Application Service: 요청의 처리에 대한 주요 로직을 담당하고, 최종적으로 응답을 WebLayer에 넘겨주는 역할을 한다.
      • Infrastructure Service: 데이터 베이스, 이메일 서버 같은 외부 서비스와 통신하는 역할을 한다. Application Service에서 Infrastructure Service를 사용한다.
  • Repository Layer
    • 가장 하위에 존재하는 Layer이다.
    • 데이터베이스와 통신하는 역할을 담당한다.

각 Layer 사이의 인터페이스 (DTO 와 Domain Model)

  • 크게 보면 DTODomain Model 이 각 Layer 사이의 변수로 넘겨진다고 볼 수 있다.
  • DTO(Data Transfer Object)
    • 데이터를 담을 수 있는 간단한 객체이다.
    • Application 내에서 각 Layer 사이의 데이터를 전달하는데 쓰인다. 응답과 요청 또한 DTO로 표현될 수 있다.
  • Domain Model
    • Domain Model은 Domain Service, Entity, VO(Value Object) 를 포함하는 개념이다.
    • Domain Service : 도메인에 대한 특정 로직을 수행하는 Stateless 한 Class 이다. 여기서 도메인은 우리가 만드는 Application을 통해 해결하고자 하는 문제 / 분야라 할 수 있다.
    • Entity : Database에 저장될 수 있는 Data를 표현하는 객체로, table과 대응된다. Entity의 Instance는 Table의 한 Row와 대응된다.
    • VO(Value Object) : 값을 표현하는 객체로, Entity와 Lifecycle을 함께한다. Entity가 갖고 있는 속성중 하나라 할 수 있다.

  • 위 그림처럼, DTO는 Web Layer와 Service Layer에서 사용된다. Web Layer는 DTO를 input으로 받고, DTO를 응답한다. 각각 Request와 Response에 대응된다 볼 수 있다.
  • Service Layer는 Web Layer로 부터 DTO 혹은 Basic Type(Int, String …) 을 넘겨 받아 로직을 수행한 후 다시 DTO를 WebLayer에 응답한다. Service Layer는 내부에서 로직을 수행하기 위해 Domain Model을 사용한다.
  • Repository Layer는 Entity와 BasicType 을 파라미터로 받고, Entity를 응답한다.

Spring의 요청 전달 과정

  1. Client는 Dispatch Servlet에 Request를 보낸다. 여기서 Request HTTP Request, 대표적으로 Method (GET, POST, PUT, PATCH, DELETE) 와 URL, 그리고 보내는 JSON Data를 포함한다.
  2. Dispatch Servlet은 HandlerMapping을 통해 요청에 대응되는 Controller를 검색하고, 응답을 받는다.
  3. Handler Adapter를 통해 Controller에 Request에 대한 처리를 요청한다.
  4. Controller, Service, Repository를 거쳐 비즈니스 로직을 수행한 후 Response를 응답한다.
  5. 다시 Handler Adpater가 응답을 Dispatch Servlet에 전달한다.
  6. 최종적으로 HTTP Response 형태의 응답이 Client에 전달된다.
  • 위 그림에서 DispatchServlet, HandlerAdapter, HandlerMapping은 Spring에서 제공하는 영역이고, Controller, Service, Repository를 구현해야 한다.

Spring의 Plumbing 방식

  • DI(Dependency Injection) & IoC(Inversion of Control)
  • Dependency Injection (의존성 주입)
    • 객체가 자체적으로 필요로 하는 의존성을 생성하는 것이 아니라, 외부에서 주입받는 디자인 패턴이다.
    • 객체간의 결합도를 낮추기 위해 사용한다.
    • 주로 Contructor 기반 주입, Field 기반 주입, Setter 기반 주입이 있다.
    • DI 가 적용되지 않은 예시, 내부에서 의존성을 생성하고 있다.
      class Dependent() {
          private val dependency = Dependency(arg1, arg2)
      }
    • Constructor를 통해 주입받는 예시
      class Dependent(private val dependency: Dependency) 
    • Field를 통해 주입 받는 예시
      class Dependent() {
          lateinit var dependency: Dependency
      }
    • Setter를 통해 주입받는 예시
      class Dependent() {
          private lateinit var dependency: Dependency
      
          fun setDependency(dependency: Dependency) {
              this.dependency = dependency
          }
      } 
    • 아래와 같은 이유에서 현업에서 주로 Constructor를 통한 주입을 사용한다.
      1. 의존되는 객체의 불변성 확보
      2. 순환 참조 방지
      3. 테스트 코드 작성의 용이

    Inversion of Control (제어의 역전)

    • Librart vs Framework 에서 설명한 것과 유사한 개념이다. Application 관점에서 라이브러리를 사용할 때는 우리가 직접 호출을 하지만, 프레임워크는 구성 요소를 등록하면, 알아서 Framework에서 호출을 한다. 이처럼 객체의 생성과 생명주기를 외부에서 제어하는 디자인 패턴이라 할 수 있다.
    • DI랑 비슷한 느낌이지만 IoC는 넓은 의미로, IoC를 구현하는 방법은 여러가지가 있다. 그 중 하나가 DI라 할 수 있다. 의존성들에 대해 제어의 역전이 되는 거라 생각할 수 있다.
    • Framework에서 IoC를 제공할 때, 이를 IoC Container라고 부른다. Spring에서는 IoC의 방식중 DI 를 주로 사용하기 때문에, 최근에는 DI Container라고 불리기도 한다.
    • 이 DI Container를 통해서, 작성한 Class의 관리를 크게 신경쓰지 않고, Spring에 맡길 수 있다.

Spring Bean과 Spring Bean을 등록하는 방법

  • Spring Bean

    • Spring IoC Container가 관리하는 객체를 Spring Bean 이라 한다.
  • Spring Bean을 등록하는 방법
    기본적으로 @Component Annotation을 통해 이루어진다. Annotation은 Kotlin 및 Java에서 사용되는 메타데이터의 일종으로, @로 시작되며 프로그램 코드에 부가적인 정보를 제공해주는 역할을 한다. 아래와 같이 클래스를 Spring Bean으로 등록할 수 있다.

@Component
class Dependency()

Bean Configuration 파일을 활용하는 방법을 통해서도 가능하다. @Configuration 과 @Bean Annotation을 통해 등록할 수 있다.

@Configuration
class DependencyConfiguration() {

    @Bean
    fun exampleDependency(): Dependency {
        return Dependency()
    }
}

다른 Annotaion

  • @ComponentScan
    • @ComponentScan은 Spring이 빈을 찾을 때 어느 패키지에서 검색할지를 지정하는데 사용된다.
    • 이 Annotation을 사용하면 Spring은 해당 패키지와 하위 패키지에서 @Component, @Service, @Repository, @Controller 등이 붙은 클래스를 스캔하여 빈으로 등록한다.
  • @Component
    • @Component는 해당 클래스를 Spring 빈으로 등록하겠다는 것을 표시하는 데 사용된다.
  • @Autowired
    • @Autowired는 필드, 생성자, 메서드에 사용되며, 해당 타입의 빈을 자동으로 주입하겠다는 의미이다.
  • @Configuration
    • @Configuration*은 Java 클래스를 Spring의 설정 파일로 지정합니다. 해당 클래스 내부에서 @Bean` 어노테이션을 사용하여 빈을 정의할 수 있다.
profile
즐겁게

0개의 댓글