책읽기

[스프링 인 액션][Part-1 스프링 기초][Ch-1] 스프링 시작하기

pythaac 2021. 7. 17. 01:42
이 글은 "스프링 인 액션 제5판 (크레이그 윌즈 지음)"을 읽고 주관적으로 작성된 글입니다.

출처 : https://jpub.tistory.com/1040

※ 배우는 내용
1) 스프링과 스프링 부트 핵심사항
2) 스프링 프로젝트 생성하기
3) 스프링 개요

 

※ 요약

  • 스프링의 목표는 개발자의 목표를 덜어주는 것
    • 웹 어플리케이션 생성
    • 데이터베이스 사용
    • 어플리케이션 보안
    • 마이크로서비스 등
  • 스프링 부트의 역할
    • 쉬운 의존성 관리
    • autoconfiguration
    • Actuator
  • 스프링 Initializr
    • 초기 설정을 해줌
    • 대부분 자바 개발 환경을 지원
  • Bean의 구성
    • 스프링 어플리케이션에서 XML/자바 등으로 선언
    • 또는 Component Scan이나 스프링 부트 autuconfiguration으로 자동 구성

 

  • 애플리케이션 개발 유형의 변화
    • 예전에는 RDBMS를 사용하는 웹 브라우저 기반 웹 애플리케이션 형태였음
    • 지금은 DB에 데이터 저장하는 클라우드에 맞춰진 마이크로서비스로 구성된 애플리케이션
    • 리액티브 프로그래밍도 새로운 관심사 : 더 큰 확장성, 향상된 성능
  • 스프링은 이러한 개발 환경을 지원
    • 마이크로서비스 / 리액티브 프로그래밍에 맞기 진화
    • 스프링 부트(Spring boot)도 추가되어 스프링 자체도 간소화됨

1. 스프링이란?

  • 보통 애플리케이션
    • 애플리케이션의 구조
      컴포넌트로 구성됨 : 애플리케이션 전체 기능 중 일부를 담당함
    • 컴포넌트의 상호작용
      컴포넌트는 다른 애플리케이션 구성 요소와 협력하여 작업 처리
    • 컴포넌트의 Requirement
      애플리케이션 실행시 컴포넌트 생성이 필요하고, 생성을 상호간 알려야함
  • 컨테이너
    • 스프링 애플리케이션 컨텍스트(Spring application context)라는 컨테이너 제공
      애플리케이션 컴포넌트들을 생성 / 관리
  • Bean
    • 컴포넌트를 빈(bean)이라 함
    • Bean들은 컨테이너 내에서 서로 연결되어 완전한 애플리케이션을 구성
    • Bean의 상호 연결
      의존성 주입(Dependency Injection)이라는 패턴 기반으로 수행
  • 컨테이너와 bean
    • 애플리케이션이 의존성을 가지는 다른 bean의 생성 / 관리를 컨테이너가 대신 해줌
    • (정리) 컨테이너의 역할
      1. 모든 컴포넌트(bean)을 생성하고 관리
      2. 이 컴포넌트에 필요한 bean을 주입
    • 이는 생성자 or 속성 접근자 메서드로 처리
  • 컴포넌트간의 관계 표현
    • 기존에는 XML로 상호 bean의 연결을 컨테이너에 알림
      각 bean이 가진 id로, 생성자 인자를 사용 -> < constructor-arg ref = $BEAN_ID />
    • 그러나 최신 버전에서는 자바 기반으로 알림
@Configuration
pulic class ServiceConfigureation{
    @Bean
    public InventoryService inventoryService() {
        return new InventoryService();
    }
    @Bean
    public ProductService productService() {
        return new ProductService(inventoryService());
    }
}
  • 어노테이션(Annotation)
    • 클래스, 인터페이스, 함수, 매개변수, 속성, 생성자에 어떤 의미를 추가하는 기능, 자바 컴파일러에서 처리
    • @Configuration
      각 bean이 컨테이너에 제공하는 구성 클래스임을 알림
    • @Bean
      각 메서드에서 반환되는 객체가 컨테이너의 bean으로 추가되어야함을 나타냄
      각 bean의 id가 해당 bean을 정의하는 메서드 이름
    • 그러나 자바 기반 알림도 auto-configuration을 할 수 없는 경우에만 사용
  • 자동-구성(Autoconfiguration)
    • 자동 연결(Autowiring)과 컴포넌트 검색(Component Scanning)이라는 스프링 기법이 기반
    • 애플리케이션의 classpath에 지정된 컴포넌트로 컨테이너의 bean을 생성
    • 의존 관계의 컴포넌트를 자동으로 다른 bean에 주입
  • 스프링 부트(Spring boot)
    • 생산성 향상을 제공하는 스프링 프레임워크의 확장
    • 향상된 Autoconfiguration
      환경 변수인 classpath를 기준으로 컴포넌트 구성과 의존성을 인지
    • 스프링 부트의 Autoconfiguration으로 애플리케이션 빌드에 필요한 별도 구성코드(XML, Java)가 현저히 줄어듬

 

2. 스프링 애플리케이션 초기 설정하기

  • 스프링 Initializr
    • 애플리케이션의 프로젝트 디렉터리 구조 생성 / 빌드 명세를 직접 정의할 수 있음
    • 그러나 시간낭비이므로, 애플리케이션 초기설정을 해주는 스프링 Initializr 사용
    • 스프링 Initializr
      - 스프링 Initialzr는 REST API를 사용하는 브라우저 기반의 웹 애플리케이션
      - 스프링 프로젝트의 구조를 생성해줌
  • Spring Tool Suite(STS)
    • 이클립스 기반 스프링 IDE
    • 다른 IDE에 없는 스프링 부트 대시보드 기능 제공
      (라고 되어있지만 내가 사용하는 Intellij도 제공하는 것으로 보임)

1) STS를 사용해서 스프링 프로젝트 초기 설정하기 (나에게 필요한 부분만 정리)

  • WAR(Web application ARchive)와 JAR(Java ARchive)
    • 기존 자바 웹 애플리케이션은 WAR로 패키징, JAR는 라이브러리와 데스크탑 UI 애플리케이션의 패키징
    • JAR 패키징은 클라우드를 염두
      - WAR는 기존 자바 애플리케이션 서버에 배포할 때 적합
      - 그러나 대부분 클라우드 플랫폼에 맞음
  • 추가하는 의존성
    • Spring Boot DevTools
    • Lombok
    • Thymeleaf
    • Spring Web

2) 스프링 프로젝트 구조 살펴보기

  • 전형적인 Maven/Gradle 구조
    • 애플리케이션 소스코드 (src/main/java)
    • 테스트 코드 (src/test/java)
    • 자바가 아닌 리소스 (src/main/resources)
  • 그 외 알아둘 항목들
    • mvnw / mvnw.cmd ( gradlew / gradle.bat )
      - Maven(Gradle) Wrapper 스크립트로, PC에 Maven(Gradle)설치 없이 프로젝트 빌드
    • pom.xml ( build.gradle )
      - Maven(Gradle) 빌드 명세 : 빌드에 필요한 정보 및 지정한 파일
    • src/main/resources/application.properties
      - 구성 속성을 직접 지정할 수 있음
    • src/main/resources/static
      - 브라우저에 제공할 정적 콘텐츠(이미지, 스타일시트, 자바스크립트 등)
    • src/main/resources/templates
      - 브라우저에 콘텐츠를 보여주는 템플릿 파일의 폴더, Thymeleaf 템플릿 추가하는 곳

빌드 명세 (Gradle을 사용하지만, pom.xml을 살펴보는 것도 도움이 될듯) 

  • 스프링 initializr가 프로젝트 생성시 내가 정의한 내용을 pom.xml( build.gradle )에 저장
  • <parent>
    • 부모 POM(Project Object Model)으로 spring-boot-starter-parent를 갖는 것을 지정
      (Gradle에서는 보이지 않음)
    • 이 POM은 스프링 프로젝트에 흔히 사용되는 여러 라이브러리의 의존성 관리를 제공
    • <version>은 해당 스프링 부트 버전에 의해 정의된 의존성 관리를 계승
  • <dependencies>
    • 의존성 정의
  • <artifactId> 에 스프링 부트 스타터(starter) 의존성의 장점
    1. 우리가 필요로 하는 모든 라이브러리 의존성에 대한 선언 생략
      - 빌드 파일 간소화
    2. 의존성을 라이브러리 이름이 아닌 기능 관점으로 파악 가능
    3. 스프링 부트에 포함되는 라이브러리의 버전 호환이 보장됨
  • <plugin> 에 스프링 부트 플러그인 기능
    1. Maven을 사용하는 애플리케이션 실행을 가능하게 해줌
    2. 의존성에 지정된 라이브러리가 실행 가능 JAR에 포함되어 있는지, 런타임시 classpath에서 찾을 수 있는지 확인
    3. 실행 가능 JAR의 main class로 부트스트랩 class를 나타내는 매니페스트 파일을 JAR로 생성

애플리케이션의 부트스트랩(구동)

  • 실행을 위해 JAR 파일에는 부트스트랩 class를 포함한 최소한의 스프링 구성을 필요로 함
  • @SpringBootApplication
    • 스프링 부트 애플리케이션임을 나타냄
    • 아래 어노테이션들을 포함하는 개념
      1. @SpringBootConfiguration
        - 현재 class를 구성 class로 지정
      2. @EnableAutoConfiguration
        - Autoconfiguration 활성화
      3. @ComponentScan
        - 컴포넌트 검색 활성화
        - @Component, @Controller, @Service 등 어노테이션과 함께 class를 선언할 수 있게 해줌
        - 스프링이 자동으로 이런 class를 찾아 컨테이너에 컴포넌트를 등록
  • 부트스트랩 class의 main 메서드
    • JAR가 실행될 때 호출 : 대부분 이름만 다르고 같은 메서드를 가짐
    • SpringApplication class의 run 메서드 실행
      SpringApplication class : 실제로 애플리케이션을 시작시키고, 스프링 애플리케이션 컨텍스트(컨테이너)를 생성함
  • 부트스트랩 Class의 수정
    • 보통 내용을 변경할 필요가 없음
    • 그러나 Autoconfiguration이 되지 않는 것을 고려하여, 별도의 구성 class를 생성하는 것이 좋음

애플리케이션 테스트하기

  • 스프링 Initializr는 테스트 클래스를 제공
  • 실행 코드가 없음
    • 그럼에도 스프링 어플리케이션 컨텍스트가 정상적으로 로드되는지 확인
  • @SpringBootTest
    • 테스트를 시작하라는 것을 JUnit에게 알림
    • main 메서드의 SpringApplication.run() 호출에 부합되는 테스트 class
  • @Test
    • 테스트 메서드
    • 테스트 메서드가 없으면 아무 일도 하지 않음

 

3. 스프링 애플리케이션 작성하기

  • 홈페이지를 추가하여, 다음 두가지 생성을 통해 스프링의 장점 확인하기
    1. 홈페이지의 웹 요청을 처리하는 컨트롤러
    2. 홈페이지의 모습을 정의하는 뷰 템플릿

1) 웹 요청 처리하기

  • 스프링 MVC
    • 웹 프레임워크
    • 컨트롤러
      - 웹 요청과 응답을 처리하는 컴포넌트
    • 웹 브라우저를 상대하는 애플리케이션의 경우 내부 동작
      - 컨트롤러는 모델 데이터를 채워서 응답
      - 브라우저에 반환되는 HTML 생성 목적으로 응답의 웹 요청을 뷰에 전달
  • 예제 컨트롤러 클래스
    1. 루트 경로(/)의 웹 요청을 처리
    2. 모델 데이터를 채우지 않음
    3. 웹 요청을 홈페이지 뷰에 전달
package tacos;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

// 컨트롤러
@Controller
public class HomeController{
    
    // 루트 경로인 /의 웹 요청을 처리
    @GetMappling("/")
    public String home(){
        // 뷰 이름을 반환
        return "home";
    }
}
  • @Controller
    • 컴포넌트 검색(Conponent Scanning)시 Home Controller를 컴포넌트로 식별하게 해줌
    • 스프링의 컴포넌트 검색에서 자동으로 Home Controller 클래스를 찾음
    • 찾은 후 스프링 애플리케이션 컨텍스트의 bean으로 인스턴스 생성
    • @Component, @Service, @Repository 모두 같은 기능 (단지 역할이 명확해서 @Controller를 사용)
  • home() 메서드의 @GetMapping
    • 루트 경로인 /의 HTTP GET 요청이 수신되면 해당 메서드 처리
    • 여기서 home 값을 갖는 String만 반환하고 다른 일은 하지 않는다. 이 값은 뷰의 논리적인 이름이다.
      - [???] 뷰의 논리적 이름이 home -> 어디서 확인할 수 있는지?
    • Thymeleaf
      - classpath에 지정되어있음
      - 이를 이용해 뷰 템플릿 정의
  • Thymeleaf
    • JSP / FreeMarker 등을 선택하지 않고 Thymeleaf를 템플릿 엔진으로 선택
    • 그 이유는 JSP를 스프링 부트와 사용시 고려할 것이 있기 때문 (2장에서 살펴볼 예정이라고 함)
    • 논리적인 뷰 이름(home) 기반으로 파일이름 생성
      - /src/main/resources/templates/home.html

 

2) 뷰 정의하기

  • 예제 홈페이지 템플릿
    • <img> 태그에서 Thymeleaf의 th:src 속성을 사용
    • /images/TacoCloud.png의 위치는 /resouces/static/images/TacoCloud.png
<!DOCTYPE html>
<html xmln="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="EUC-KR">
    <title>Taco Cloud</title>
</head>
<body>
    <h1> Welcom to...</h1>
    <img th:src="@{/images/TacoCloud.png}"/>
</body>
</html>

3) 컨트롤러 테스트하기

  • 스프링은 웹 어플리케이션을 쉽게 테스트하는 강력한 테스트 지원 기능 제공
    • HTML 페이지의 콘텐츠에 대한 assertion을 설정하기 어려움
    • assertion : 우리가 원하는 것이 맞는지 테스트하기 위해 지정한 단언
  • 테스트할 내용
    1. /의 HTTP GET 요청이 성공적인지 (status가 200인지)
    2. 뷰의 이름이 home인지
    3. "Wlecome to..." 메시지가 포함되어 있는지
  • @WebMvcTest
    • @SpringBootTest 대신 사용
    • 스프링 MVC 어플리케이션 형태로 테스트가 진행
      - HomeController가 스프링 MVC에 등록되어 웹 요청을 보낼 수 있음
  • MockMvc 객체
    • 실제 서버를 시작하지 않고 모의 테스트
    • 스프링 MVC의 모의(mocking) 매커니즘 사용
    • mockMvc.perform(get("/")
      - /의 HTTP GET 요청을 MockMvc 객체로 수행
    • andExpect
      - 기대하는 결과를 설정
@WebMvcTest(HomeController.class)
public class HomeControllerTest {
	@Autowired
	private MockMvc mockMvc;
	@Test
	public void testHomePage() throws Exception {
		mockMvc.perform(get("/"))
		.andExpect(status().isOk())
		.andExpect(view().name("home"))
		.andExpect(content().string(
				containsString("Welcome to...")));
	}
}

4) 애플리케이션 빌드하고 실행하기

  • 스프링 부트 대시보드
    • IDE에서 실행중인 어플리케이션의 로그를 보여주는 기능을 말하는듯
    • Intellij에서 services라는 tab이며, 실행시 자동으로 활성화되는 듯
  • tomcat은 어플리케이션의 일부
    • tomcat에 어플리케이션을 설치하지 않았는데 실행이 가능
    • 스프링 부트 어플리케이션에 실행에 필요한 모든 것이 포함되기 때문

5) 스프링 부트 DevTools 알아보기

  • 개발 시점에서 편리한 도구들을 제공
    1. 코드 변경시, 자동으로 어플리케이션 재시작
    2. 리소스 변경시, 자동으로 브라우저 새로고침 / 템플릿 캐시 비활성화
    3. H2 콘솔 활성화
  • 자동 어플리케이션 재시작
    • 자바 코드 / 속성 파일 변경시 감지하여 어플리케이션 재시작
    • DevTools 사용 중일때는 JVM에 2개의 클래스 로더에 의해 로드
      1. src/main/ 경로에 있는 자바 코드 / 속성 파일를 포함
      2. 의존성 라이브러리를 포함
    • 1번 클래스 로더만 다시 로드
      - 시간이 조금이나마 단축
      - 빌드 명세에 의존성 추가/변경/삭제 등 의존성 변경시 직접 새로 시작해야함
  • 자동 브라우저 새로고침 / 템플릿 캐시 비활성화
    • 성능 향상을 위해 템플릿의 파싱 결과를 캐시에 저장
    • 개발 시점에서 이는 새로고침을 하더라도 변경사항이 적용되지 않으므로 불편함
    • DevTools는 모든 템플릿 캐싱을 자동으로 비활성화 -> 새로고침시 변경내용이 적용
    • LiveReload를 사용할 경우, 새로고침까지 자동
  • H2 콘솔
    • H2 DB를 사용할 시, H2 콘솔도 DevTools가 자동으로 활성화
    • http://localhost:8080/h2-console에 접속하면 확인 가능

6) 리뷰하기

  • 지금까지 만든 스프링 어플리케이션 작업 과정
    • 스프링 Initializr로 프로젝트 구조 생성
    • 컨트롤러 클래스 작성
      - 홈페이지 웹 요청 처리
    • 뷰 템플릿 정의
      - 홈페이지를 보여주는 역할
    • 테스트 클래스 작성
      - 애플리케이션 테스트
  • 스프링을 사용한 어플리케이션의 장점
    • 어플리케이션의 요구를 충족하는 코드에 집중할 수 있음
      - 작성한 코드가 간단함
    • 스프링이 빌드명세에 따라 dependency injection을 함
      - 빌드 명세(pom.xml)에 Web과 Thymeleaf 의존성을 선언
      - 스프링 MVC 프레임워크 / 내장 tomcat / Thymeleaf, Thymeleaf 레이아웃 dialect 등 의존성을 포함시킴
      - 이에 따라 관련된 bean / tomcat 서버를 스프링 어플리케이션 컨텍스트에 구성
      - Thymeleaf 뷰 리졸버를 구성

 

4. 스프링 살펴보기

1) 핵심 스프링 프레임워크

  • 스프링 MVC
    • 웹 요청 처리 (REST API)
  • JdbcTemplate
    • JDBC 지원 (데이터 퍼시스턴스)
  • WebFlux
    • 리액티브 프로그래밍

2) 스프링 부트

  • 스타터 의존성 / autuconfiguration
  • 액추에이터(Actuator)
    • 어플리케이션의 내부 동작을 runtime에 살펴볼 수 있는 기능
    • metric / thread dump 정보 / 어플리케이션 상태 / 사용 환경 포함
  • 환경 속성의 명세
  • 테스트 지원
  • 스프링 부트 CLI 제공
    • 어플리케이션 전체를 그루비 스크립트로 작성하여 CLI에서 실행

3) 스프링 데이터

  • 간단한 자바 인터페이스로 어플리케이션의 데이터 repository 정의 가능
  • 서로 다른 종류이 DB와 함께 사용 가능

4) 스프링 시큐리티

  • 인증(Authentication) / 허가(Authorization) / API 보안을 포함한 강력한 보안 프레임워크

5) 스프링 통합과 배치

  • 다른 어플리케이션 / 다른 컴포넌트를 통합할 필요가 생김
    • 이미 알려진 몇 가지 애플리케이션 통합 패턴이 있음
  • 스프링 통합
    • 데이터가 사용 가능한 즉시 처리되는 실시간 통합
  • 스프링 배치
    • 다량의 데이터가 처리되는 시점을 트리거가 알려줄 때 데이터가 수집 처리되는 배치 통합 처리

6) 스프링 클라우드

  • 어플리케이션 개발 세계가 새로운 시대로 진입중
  • 어플리케이션을 거대한 하나의 단일체 대신 여러 개의 개별적 단위들로 합성
  • 스프링 클라우드는 클라우드 어플리케이션 개발을 위한 프로젝트 모음