Spring & JPA

스프링 부트 특징과 Spring Bean, Spring MVC

진진리 2025. 4. 13. 14:09

스프링 부트의 특징

  1. stand-alone
    • 독립 실행형 스프링 애플리케이션 개발 가능
      • 이전에는 WAS를 설치 및 설정하고 개발한 애플리케이션을 WAR 형식으로 패키징하여 WAS에 배포
    • 서버에 별도로 WAS를 설치하지 않고도 개발 시작 가능, WAS 관리 등의 작업 부담이 줄어듦
    • 내장 서버 지원
      • 내장 톰캣과 같은 내장 서버를 라이브러리 형태로 함께 패키징
      • 앱 시작 시점에 내장 서버를 초기화 및 실행
      • 원하는 환경 어디에서든 독립적으로 실행 가능
  2. opinionated
    • 스프링 프레임워크는 자유로운 선택지(라이브러리 등) 제공 -> 빠른 애플리케이션 개발을 방해할 수 있음
    • starter: best-practice라고 알려진 라이브러리 조합을 미리 모아둔 것
      • 프로젝트 초기 생성 시 의사결정 과정을 생략하고 빠르게 개발을 시작
      • spring-boot-starter-web
    • 라이브러리 버전 결정, 의존성 버전 관리
  3. auto-configuration
    • 필요한 스프링 빈들을 자동으로 스프링 컨테이너에 등록해주는 기능
      1. classpath에 존재하는 모든 라이브러리 순회
      2. 각 라이브러리의 특별한 파일을 읽어옴
      3. 읽어온 정보를 바탕으로 어떤 설정 클래스를 사용할지 선택
      4. 이후 설정 클래스의 @Bean이 적용된 메서드를 실행하며, 반환된 객체를 빈으로 등록
    • 특별한 파일: AutoConfiguration.imports
      • 자동 구성에 사용할 설정 클래스(@Configuration)의 className을 모아둠
    • ImportSelector
      • 동적으로 설정 파일(@Configuration)을 읽어올 수 있도록 하는 인터페이스
      • 구현체는 selectImports() 메서드를 구현해야 함 -> 설정 클래스들의 className을 담은 배열 반환
      • 자동 구성을 위한 AutoConfigurationImportSelector를 제공
    • spring-boot-autoconfigure
      • 자주 사용하는 라이브러리의 경우 자동 구성 설정 클래스르 제공
      • jackson, jdbc 등

 

스프링 프레임워크

  • 자바 기반의 어플리케이션을 만들 수 있다.
  • 개발자들은 비즈니스 로직에 집중할 수 있다.
  • 이전 EJB라는 프레임워크가 존재
    • 목적: 비즈니스 로직과 앤터프라이즈 기술의 분리
    • 실제: 너무 비싸고 EJB에 의존적이고 종속적
  • 문제점: 스프링 생태계와 기능이 커짐. 외부 라이브러리를 함께 사용할 일이 많아짐 -> 초반 설정에 많은 시간이 필요
  • Spring Boot의 등장

스프링 빈

  • 스프링 빈: 스프링 IoC 컨테이너가 관리하는 객체
  • 스프링 IoC 컨테이너: 빈을 관리하는 객체

왜 스프링 빈의 필요할까?

  • 빈과 의존성 주입: 의존성 주입이 필요한 객체를 빈으로 등록하여 스프링 부트가 자동으로 주입해줌
  • 빈과 싱글턴
    • 싱글턴의 단점: 생성자의 접근제어자를 private으로 설정해 다형성을 적용하기 어려움, 단위 테스트가 어려움
  • 스프링 빈이 필요한 이유: 스프링 IoC 컨테이너가 특정 객체의 라이프사이클을 관리한다는 것을 명시

스프링 IoC 컨테이너는 어떻게 빈을 관리할까?

  • 빈을 관리하는 방법: 객체 생성 + property 설정 -> 의존 설정 -> 초기화 -> 사용 -> 소멸
    • Configuration Metadata(XML, Annotation, Java Config)를 사용해 Bean Definition을 생성
    • Bean Definition과 Plain Old Java Objects로 빈 객체를 생성
  • 스프링 IoC 컨테이너는 Singleton Registry(key-value 형태로 저장)를 가짐
    • 싱클톤인 객체인 빈의 이름을 key로, 객체를 value로 사용
    • 동일한 객체를 반환하여 싱글톤 객체로 사용
  • 스프링 IoC 컨테이너는 왜 빈을 관리할까?
    • 의존성을 사용하는 로직에만 집중 가능
    • 의존성 주입될 객체가 동일한 싱글 오브젝트임을 보장

빈 설정 시 주의점

  • 여러 메서드가 상태를 변경 시킬 수 있으므로 빈 스코프가 싱글톤인 경우 상태를 가지면 안됨
    • 빈 스코프가 @Scope("prototype")인 경우 요청이 올 때마다 생성되기 때문에 상태를 가질 수 있음
  • 자동 주입할 인터페이스의 구현체가 2개 이상이라면 충돌 발생
    • @Primary : 우선 순위 설정하여 자동 주입하도록 함
    • @Qualifier("구현체 이름") : 특정 구현체를 주입하도록 설정 가능
  • @Component의 경우 @Configuration과 달리 프록시 처리를 하지 않아 싱글톤을 보장하지 않음

Servlet

  • 웹 서버 : 정적 페이지 제공
  • WAS : 로직을 수행해서 동적 컨텐츠 생성
  • Servlet: 동적 컨텐츠를 만드는데 사용되는 자바 기반의 웹 어플리케이션 프로그래밍 기술 혹은 사용되는 객체
    • service() 메서드로 ServletRequest를 비즈니스 로직으로 처리해 ServletResponse로 응답
    • Sevlet <- GenericServlet <- HttpServlet : 표준 프로토콜인 Http 요청과 응답을 다룸
      • doGet(), doPost(), doPut() 메서드를 가짐
    • 필요한 Servlet을 HttpServlet을 상속받아 직접 구현
  • WAS에서 Servlet이 실행되는 방법
    • 초기: web.xml에서 url-pattern에 해당하는 servlet을 매핑해둠
    • Sevlet 3.0 버전 이후로는 어노테이션으로 간단하게 등록 가능
@WebServlet(name = "cartServlet", urlPatterns = "/cart")
public class CartServlet extends HttpServlet {
	
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    // ... 

}
  • Servlet을 이용한 웹 요청과 응답 과정
    • Servlet 기술을 지원하는 WAS의 경우 - Servlet 실행 환경을 제공
    • 클라이언트가 요청을 보내면 웹 서버가 WAS에 요청을 위임하면 수행 후 응답
      • 문제점: 화면 레더링 코드의 가독성과 유지보수성이 낮음
  • JSP: HTML 코드에 Java 코드를 넣어 동적 웹 페이지를 생성하는 서버 사이드 템플릿 엔진

MVC Model

  • MVC Model 1의 한계: JSP의 비즈니스 로직과 HTML 코드 분리 x
  • MVC Model 2
    • View: 화면을 그리는 일을 수행
    • -> Controller: HTTP 요청을 받고 비즈니스 로직을 수행
    • <-> Model: 데이터와 비즈니스 로직을 담당

Spring MVC

  • 중앙에 있는 DispatcherServlet이 요청을 처리하기 위한 공유 알고리즘을 제공하는 프론트 컨트롤러 패턴을 중심으로 설계됨
  • = Spring에서 MVC 디자인 패턴을 적용하여 HTTP 요청을 효율적으로 처리
  • DispatcherServletFront Controller
    • 모든 API 요청에 무수히 많은 Servlet 클래스를 구현해야 함
    • Spring은 DispatcherServlet을 사용해 효율적으로 API 처리
      1. HTTP 요청이 들어오면 DispatcherServlet이 요청을 분석
      2. Handler mapping을 통해 Controller를 찾아 요청을 전달
      3. HandlerAdaptor는 핸들러의 종류에 관계 없이 핸들러(컨트롤러)를 실행
      4. Controller 처리 완료 후 결과인 데이터(Model)와 View 정보를 전달
      5. ViewResolver를 통해 View에 Model을 적용하여 클라이언트에게 응답


직렬화와 역직렬화

html 파일이 아닌 JSON 데이터를 반환하고 싶은 경우 @ResponseBody를 추가

Spring에서 자동으로 Java 객체를 JSON으로 변환

  • 직렬화: 객체를 바이트 스트림(Json 등)으로 변환하는 과정
  • 역직렬화: 직렬화된 바이트 스트림(Json 등)을 객체로 변환하는 과정
  • Reflection API: 구체적인 클래스 타입을 알지 못해도 그 클래스의 정보에 접근할 수 있게 해주는 자바 API

Spring Framework 직렬화 과정

  • HttpMessageConverter가 수행
  • 요청 - canRead, 응답 - canWrite : 클래스 타입을 지원하는지, Media Type을 지원하는지 확인
  • ObjectXXXX을 사용 -> Jackson 라이브러리에서 가져옴

Jackson 라이브러리

  • Spring 3.0 이후로 Jackson 관련 API를 제공, SpringBoot의 starter-web에서 제공
    • 직접 JSON 데이터를 처리해야 할 때 Jackson 라이브러리의 ObjectMapper 사용 가능
  • Jackson 라이브러리
    • Object <-> JSON 타입의 String으로 변환 가능
    • Reflection API를 활용하여 클래스 정보를 동적으로 읽어 직렬화/역직렬화
  • 직렬화 방법
    • 필드의 접근 제어자를 public으로 한다.
    • private 필드에 대해서는 표준 getter를 선언한다. -> getXxxx();
      • objectMapper의 writeValueAsString 메서드를 사용해 변환 가능
  • 역직렬화 방법 
    • 표준 Setter/Getter / 기본 생성자 / 생성자 1개 존재하면 역직렬화 가능
      • objectmapper의 readValue 메서드를 사용해 변환 가능

알면 유용한 Annotation

  • @JsonIgnore: 직렬화/역직렬화에서 특정 필드를 제외 가능
  • @JsonCreator: 역직렬화 시 생성자, 팩토리 메소드 선택 방법 결정 가능
  • @JsonProperty: Json 필드와 객체 필드 이름이나 순서를 다르게 하고 싶을 때
  • @JsonFormat: Json 응답의 날짜/시간 형식 지정 가능, 타임존 지정 가능