[책] 처음 배우는 스프링 부트2
chanpter 1 스프링부트 입문하기
스프링 역시 개발 환경 설정이 만만치 않은데 안정성, 성능, 의존성주입 등 매우 강력한 장점들 덕에 자바 대표 프레임워크로 자리잡았다.
스프링팀은 이 같은 단점을 보완하고자 스프링부트를 만들었다.
스타터는 애플리케이션에 포함되는 편리한 의존성 집합체.
스타터를 사용하면 의존성을 일일이 찾지 않고도 모든 필요한 스프링 관련 기술을 한번에 도입할 수 있다.
스프링 부트는 필요한 환경 설정을 최소화하고 개발자가 비즈니스 로직에 집중할 수 있도록 도와줘 생산성을 크게 향상시킨다.
스프링부트는 스프링 프레임워크라는 큰 틀에 속하는 도구!
스프링 부트 특징
- 임베디드 톰캣, 제티, 언더토우를 사용하여 독립 실행이 가능한 스프링 애플리케이션 개발
- 통합 스타터를 제공하여 메이븐/그레들 구성 간소화
- 스타터를 통한 자동화된 스프링 설정 제공
- 번거로운 XML 설정 요구 X
- JAR를 사용하여 자바 옵션만으로도 배포 가능
- 애플리케이션의 모니터링과 관리를 위한 스프링 액츄에이터 제공
스타터란? 특정 목적을 달성하기 위한 의존성 그룹! - 빌드에 필요한 의존성을 자동으로 관리함
스타터 내부의 의존성을 확인하는 방법
-
의존관계가 궁금할때, Spring Boot Reference Guide Table 13.1. Spring Boot application starters 에서
Pom
확인 -
의존관계를 확인하지 않고 spring-boot-starter를 추가했는데 의존 관계 설정이 궁금할 때,
External Libraies
를 펼쳐서 확인 가능
spring-boot-starter 에서 제공하는 의존성 (1번으로 본 pom.xml 의 artifactId)
- spring-boot : 스프링 부트에서 제공하는 기본 의존성
- spring-boot-autoconfigure : 스프링 부트의 자동 환경 구성에 필요한 의존성
- spring-boot-starter-logging : 각종 로그를 사용하는 데 필요한 의존성
- javax.annotation-api : 소프트웨어의 결함을 탐지하는 어노테이션을 지원하는 의존성
- spring-core : 스프링 코어를 사용하는 데 필요한 의존성
- snakeyaml : yaml을 사용하는데 필요한 의존성
스프링부트 프로젝트의 의존성을 다룬 문서는 모두 깃헙에 공개되어 있다. 약 170여 가지에 대한 버전이 명시되어있음.. 여기서 확인
- 버전에 따라 기존 API지원 형식이나 서로 의존되는 정보가 달라지는 경우도 있기 때문에 자신이 사용하는 라이브러리 버전 정도는 확인해 주는것이 좋다 :)
스프링 부트 버전에 따라 무엇이 다른지 어떻게 알 수 있을까
->스프링 부트의 Wiki 페이지를 본다 ‘Releasee Notes’ 항목에서 원하는 버전 확인!
스프링 부트 장단점 (개인차 존재)
장점
- 각각의 의존성 버전을 올리는 것이 좀 더 수월.
- 특정 라이브러리에 버그가 있다 하더라도 스프링팀에서 버그픽스한 버전을 받기 편리함
- 간단한 어노테이션 설정과 프로퍼티 설정으로 원하는 기능을 빠르게 적용 가능
- 별도의 외장 톰캣 설치 불필요 & 톰캣 버전도 더욱 편리하게 관리됨⭐️
단점
- 커스터마이징한 설정을 하면 버전을 올릴 때 스프링을 사용하는 것과 동일한 불편햠 겪음
- 설정을 커스터마이징 하거나 설정 자체를 변경하려면 내부 설정 코드를 봐야하는 불편함
chanpter 2 스프링 부트 환경 설정
Gradle은 Maven과 마찬가지로 규칙 기반으로 빌드를 구성할 수 있다. 또한 JVM 환경 언어인 Groovy로 만들어져 언어의 장점을 그대로 활용할 수 있으며, 테스크를 사용하면 빌드 순서까지 제어할 수 있다.
메이븐 설정 파일인 pom.xml은 XML기반으로 작성되어 있어서 동적인 행위에 제약이 있다. 그래서 대안으로 나온 그루비 기반의 그레들이 주목받고 있다.
그레들은 (=Ant로부터 기본적인 빌드 도구 기능 + 메이븐으로부터 의존 라이브러리 관리 기능) 멀티 프로젝트 구성 시에는 메이븐처럼 상속 구조가 아닌 설정주입 방식을 사용하여 훨씬 유연하게 빌드 환경을 구성할 수 있다.
그레들 설정 관련 기본 구조
┣━gradle
┃ ┗━wrapper
┃ ┣━gradle-wrapper.jar
┃ ┗━gradle-wrapper.properties
┣━gradlew :리눅스 및 맥 os용 셀 스크립트
┗━gradlew.bat :윈도우용 배치 스크립트
그런데 왜 그레들을 자동으로 설치할까? 위의 그림은 gradle wrapper와 관련된 설정이며 프로젝트 첫 설정 시 그레들 관련 빌드 설정을 자동으로 해주기 때문 !
그레들 래퍼를 설치하여 깃과 같은 VCS에서 관리하면 공동 작업자들이 그레들 설치 및 버전 관리를 편리하게 할 수 있다. 그레들 버전 변경은 gradle-wrapper.properties 에서 disctributionUrl을 원하는 버전으로 수정하면 끝. 맥OS나 리눅스라면 gradlew 셸 스크립트를 실행한다.
$ chmod 755 gradlew //권한이 없다고 하면 실행 권한을 추가
$ ./gradlew wrapper --gradle-version 4.8.1 //4.8.1 버전으로 그래들 버전 수정
$ ./gradlew -v //그래들 버전 확인
그래들 멀티 프로젝트 구성하기
그레들 멀티 프로젝트를 활용하면 여러 프로젝트를 마치 하나의 프로젝트처럼 사용할 수 있다. 일반적으로 공통 코드를 하나의 프로젝트로 분리하고 이를 재사용할 때 유용 !
- 그레들 설정파일인 setting.gradle에 다음같이 루트 프로젝트를 추가한다. 특정한 명령 규칙에 따라 그레들에서 자동으로 인식하여 설정된다.
rootProject.name = 'demo'
- 테스트로 사용할 demo-web 모듈과 공용으로 사용할 demo-domain 생성. 설정파일에 가보면 자동으로 인클루드 되어있다.
rootProject.name = 'demo' include 'demo-web
최종 완성된 모듈 구조
┣━.gradle
┣━.idea
┣━gradle
┣━demo-domain
┃ ┗━src
┃ ┣━main
┃ ┃ ┗━java
┃ ┃ ┗━com
┃ ┃ ┗━demo
┃ ┗━test
┃ ┗━java
┃ ┗━com
┃ ┗━demo
┗━demo-web
┗━src
┣━main
┃ ┣━━java
┃ ┃ ┗━com
┃ ┃ ┗━demo
┃ ┗━resources
┃ ┣━static
┃ ┗━templates
┗━test
┗━java
┗━com
┗━demo
멀티 프로젝트를 구성하면 코드 재사용성이 높아지고 한 서비스에 관련된 여러 프로젝트를 마치 하나의 통합 프로젝트처럼 관리할 수 있다.
스프링 부트 프로퍼티 파일은 설정 관련 및 기타 정적인 값을 키값 형식으로 관리한다. 기존 스프링 프레임워크의 복잡한 XML설정을 파일 하나로 설정할 수 있다.
프로퍼티 파일의 표현의 한계 때문에 YAML파일을 더 많이 사용함. 설정값의 깊이에 따라 들여쓰기를 해서 계층 구조를 훨씬 쉽게 파악 가능. (YMAL Ain’t Markup Language. 가독성이 좋으며 문법이 이해하기 수월하도록 작성된 언어)
YAML을 설정하려면 SnakeYAML 라이브러리를 포함해야 하지만 스프링 부트 스타터에 기본적으로 내장되어 있어 바로 사용 가능하다.
⚠️ 만약 application.properties와 application.yml 파일이 둘 다 있으면 yml만 오버라이드되어 적용된다.
프로파일에 따라 프로퍼티를 다르게 설정
실제 서비스에서 개발을 하면 로컬, 개발, 운영 각각의 설정값이 다르게 된다. 이런 경우 프로파일에 따라 프로퍼티를 다르게 설정해 주어야함.
YAML 파일에서는 — 을 기준으로 설정값을 나눈다.
server:
port: 80
---
spring:
profiles: local
server:
port:8080
---
spring:
profiles: dev
server:
port:8081
최상단에 설정한 부분은 프로파일과는 상관없이 디폴트로 정의되는 영역
또 다른 방법은 application-{profile}.yml 을 이용하는 것. {profile}에 원하는 프로파일 값으로 YAML 파일을 추가하면 애플리케이션 실행 시 지정한 프로파일값을 바탕으로 실행된다.
스프링 부트 프로젝트는 JAR파일로 빌드하여 서버에서 직접 간단한 명령으로 실행할 수 있다.
각각의 프로파일값을 따로 지정하여 애플리케이션을 실행한다고 가정할때 터미널에서 다음과 같이 실행해 프로파일값을 활성화할 수 있다.
$ java -jar ... -D spring.profiles.active=dev
(…아득…)
h2는 메모리 데이터베이스로 보통 테스트용으로만 쓰인다. 주 저장소가 아니기 때문에 불필요한 컴파일 의존성에 포함될 필요가 없다.
chanpter 3 스프링 부트 테스트
스타터는 크게 두 가지 모듈로 구성 된다. spring-boot-test 와 spring-boot-test-autoconfigure 이며 테스트 관련 자동 설정 기능을 제공한다. 보통 spring-boot-starter-test 로 두 모듈을 함께 사용한다.
스프링 부트 1.4 부터는 각종 테스트를 위한 어노테이션 기반 기능을 제공하여 특정 주제에 맞게 테스트를 구현하고 관리할 수 있다.
@SpringBootTest @WebMvcTest @DataJpaTest @RestClientTest @JsonTest 등 자주 사용하는 어노테이션 위주로 살펴본다.
@SpringBootTest : 만능
통합 테스트를 제공하는 기본적인 스프링 부트 테스트 어노테이션. 애플리케이션이 실행될 때의 설정을 임의로 바꾸어 테스트를 진행할 수 있으며 여러 단위 테스트를 하나의 통합된 테스트로 수행할 때 적합하다. 프로젝트를 만들면 메인클래스와 함께 기본으로 제공된다.
실제 구동되는 애플리케이션과 똑같이 애플리케이션 컨텍스트를 로드하여 테스트하기 때문에 하고 싶은 테스트를 모두 수행할 수 있다. 단 애플리케이션에 설정된 빈을 모두 로드하기 때문에 규모가 클수록 느려지게되고 단위 테스트라는 의미가 희석된다.
chanpter 5 스프링 부트 시큐리티 + OAuth2
스프링 부트 시큐리티는 스프링 시큐리티의 번거로운 설정을 간소화시켜주는 래핑 프레임워크. 스프링 시큐리티는 기본적인 틀 안에서 원하는 대로 인증, 권한 처리를 편하게 관리할수있다.
가장 중요한 개념은 인증과 권한부여.
- 인증 : 사용자(클라이언트)가 애플리케이션의 특정 동작에 관하여 허락(인증)된 사용자인지 확인하는 절차
- 권한 부여 : 데이터나 프로그램 등의 특정 자원이나 서비스에 접근할 수 있는 권한을 허용 하는 것.
인증방식에는 전통적인 사용자명(principle)과 비밀번호(credential)로 인증하는 credential기반 인증방식 / OTP와 같이 추가적인 인증 방식을 도입해 2가지 방법으로 인증하는 이중인증 방식 / 소셜 미디어를 사용해 편리하게 인증하는 OAuth2 인증 방식 등
OAuth2 : 토큰을 사용한 범용적인 방법의 인증을 제공하는 표준 인증 프로토콜
이 프로토콜은 서드파티(제3자, 프로토콜이나 관련된 사항이 아닌 다른 리소스)를 위한 범용적인 인증 표준이다. 승인타입은 총 4가지.
- 권한 부여 코드 승인 타입(Authorization Code Grant Type): 클라이언트가 다른 사용자 대신 특정 리소스에 접근을 요청할때 사용된다. 리소스접근을 위한 사용자명과 비밀번호, 권한 서버에 요청해서 받은 권한 코드를 함께 활용해 리소스에 대한 액세스 토큰을 받으면 이를 인증에 이용하는 방식.
- 암시적 승인 타입(Implicit Grant Type) : 권한 부여 코드 승인 타입과 다르게 권한 코드 교환 단계 없이 액세스 토큰을 즉시 반환받아 이를 인증에 이용하는 방식.
- 리소스 소유자 암호 자격증명 승인 타입(Resource Owner Password Credentials Grant Type) : 클라이언트가 암호를 사용하여 액세스 토큰에 대한 사용자의 자격 증명을 교환하는 방식
- 클라이언트 자격 증명 승인 타입(Client Credentials Grant Type) : 클라이언트가 컨텍스트 외부에서 액세스 토큰을 얻어 특정 리소스에 접근을 요청할 때 사용하는 방식
chanpter 6 스프링 부트 데이터 레스트
단일 서버로 데이터를 관리하며 유연하게 클라이언트 영역을 대응할 수 있는 방법이 바로 REST 서버이다. 클라이언트는 단지 REST 서버를 통해 데이터를 받아와서 각 기기별로 대응하면 된다.
REST는 웹의 장점을 극대화하는 통신 네트워크 아키텍처. REST의 구현 원칙을 제대로 지키는 시스템을 RESTful이라고 한다. 웹과 같은 분산 하이퍼미디어 시스템에서 사용하는 통신 네트워크 아키텍처로 네트워크 아키텍처의 원리 모음이다. HTTP는 웹에서 GET POST PUT DELETE등의 메서드를 사용하여 정보를 주고받는 프로토콜인데 REST는 HTTP와 URI(통합 자원 식별자:인터넷에서 특정 자원을 나타내는 유일한 주솟값)의 단순하고 간결한 장점을 계승한 네트워크 아키텍처이다. 따라서 다양한 요구사항에 대응하여 때로는 단순하게 때로는 서버와 클라이언트가 서로 통신하는 리소스에 대해 복잡한 방식으로 상호작용할 수 있다.
목적
- 구성요소 상호작용의 규모 확장성
- 인터페이스의 범용성
- 구성요소의 독립적인 배포
- 중간적 구성요소를 이용한 응답지연 감소, 보안 강화, 레거시 시스템 인캡슐레이션
제약 조건
- 클라이언트-서버 : 이 제약 조건의 기본 원칙은 관심사의 명확한 분리다. 관심사의 명확한 분리가 선행되면 서버의 구성요소가 단순화되고 확장성이 향상되어 여러 플랫폼을 지원할 수 있다.
- 무상태성 : 서버에 클라이언트의 상태 정보를 저장하지 않는 것. 단순히 들어오는 요청만 처리하여 구현을 더 단순화한다. 단 클라이언트의 모든 요청은 서버가 요청을 알아듣는데 필요한 모든정보를 알고 있어야 한다.
- 캐시가능 : 클라이언트의 응답을 캐시할 수 있어야 한다. HTTP의 캐시 기능도 적용할 수 있다.
- 계층화 시스템 : 서버는 중개서버(게이트웨이 프록시)나 로드 밸런싱, 공유 캐시 등의 기능을 사용하여 확장성 있는 시스템을 구성할 수 있다.
- 코드 온 디맨드 : 클라이언트는 서버에서 자바 애플릿, 자바스크립트 실행코드를 전송받아 기능을 일시적으로 확장할 수 있다.(선택가능한 제약조건)
- 인터페이스 일관성 : URI로 지정된 리소스에 균일하고 통일된 인터페이스를 제공한다. 아키텍처를 단순하게 분리하여 독립적으로 만들 수 있다.
인터페이스 일관성에대한 4가지 프로퍼티
- 자원 식별 :URI를 사용한다는 것, 정보는 ‘resource’ 유일한 구분자는 1로 식별한다. http://localhost:8080/resource/1
- 메시지를 통한 리소스 조작
- 자기 서술적 메시지 : HTTP Method와 Header를 활용해 자신을 어떻게 처리해야 하는지 충분한 정보를 포함한다.
- 애플리케이션 상태에 대한 엔진으로서의 하이퍼미디어(HATEOAS) : 클라이언트에 응답할 때 단순히 결과 데이터만 제공해주기보다는 URI를 함께 제공해야 한다는 원칙. 관련된 리소스 정보를 포함한다.
특히 제약 조건중 하이퍼텍스트를 포함하고 자기서술적이며 인터페이스 일관성을 통해 리소스에 접근하는 API여야 RESTful하다 할수 있다.(인터페이스가 일관된 표준이 있어야 함)
한 대의 서버가 여러 클라이언트에 대응하려면 REST API가 필요하고 REST API는 다음과 같이 구성해야 한다.
- 자원(resource) : URI
- 행위(verb) : HTTP 메서드
- 표현(representations) : 리소스에 대한 표현(HTTP Message Body)