상세 컨텐츠

본문 제목

02장 스프링 부트 소개

MSA

by 코농이 2021. 3. 17. 18:16

본문

스프링 부트

부트의 기반이 되는 스프링 프레임워크는 J2EE를 대체하고자 출시됨
스프링은 의존성주입(DI) 개념을 기반으로 매우 가벼운 개발 모델을 제공하며 가벼운 XML 구성 파일을 사용
스프링 애플리케이션을 설정하고자 복잡한 XML 구성 파일을 사용하는 것은 부담이 되기 시작했고
2014년에 스프링 부트 v1.0  출시
스프링부트스프링 프레임워크와 서드파티 제품으로 구성된 핵심 모듈 설정 방식을 개선하여 상용 스프링 애플리케이션을 빠르게 개발하기 위한 프레임워크 

설정보다 관례와 팻 JAR 파일

◇ 스프링부트는 다양한 관례를 기본 적용하여 구성을 최소화
◇ 필요한 경우에만 구성을 작성하여 기존 규칙을 대신
이 디자인 패턴은 초기 구성을 최소화 하며 설정보다 관례라는 이름으로 알려져 있음

◇ 독립형 JAR파일(팻 JAR 파일) 기반의 런타임 모델 지원
    ◆ 이전에는 java EE 웹 서버(ex.아파치 톰캣)에 WAR 파일로 배포해 실행하는 것이 일반적이었음
    ◆ HTTP를 사용해 REST API를 공개하는 스프링 부트 애플리케이션은 내장형 웹 서버를 포함
    ◆ 팻 JAR는 java -jar app.jar 와 같은 같단한 커맨드로 시작 - 도커 컨테이너에서 실행하기 매우 적합 

스프링 부트 애플리케이션 설정에 대한 코드 예제

@SpringBootApplication 애노테이션

@SpringBootApplication
public class MyApplication{
	public static void main(String [] args){
		SpringApplication.run(MyApplication.classm args);    
    }
}


◇ 컴포넌트 검색을 활성화해 애플리케이션 클래스와 모든 하위 패키지에서 스프링 컴포넌트와 구성 클래스 검색

◇ 애플리케이션 클래스 자체를 구성 클래스로 만듬

◇ 자동설정 활성화하여 JAR 파일을 클래스 패스에서 자동으로 찾게 함
    ◆ 톰캣이 클래스패스에 있는 경우 스프링부트는 톰캣을 내장형 웹 서버로 자동 구성

컴포넌트 검색

◇ 애플리케이션 클래스의 패키지나 하위 패키지에 스프링 컴포넌트 사용
    ◆ @autoWired 통해 자동으로 다른 애플리케이션 컴포넌트를 주입
    ◆ 다중 스레드 런타임 환경에서는 컴포넌트를 실행하려면 불변의 상태가 중요함.
        상태를 변경 할 수 없도록 생성자 주입을 사용하는 것이 좋음

//애플리케이션 클래스의 패키지나 하위 패키지에 스프링 컴포넌트가 있음을 가정
@Component
public class MyComponentImpl implements MyComponent{...


public class AnotherComponent{

    private final MyComponent myComponent;

    @Autowired //오토 와이어링
    public AnotherComponent(MyComponent MyComponent){
        this.myComponent = myComponent;
    }

◇ 애플리케이션 패키지를 벗어난 다른 패키지에 선언된 컴포넌트 사용
    ◆ 애플리케이션 클래스에 @ComponentScan 애노테이션을 사용하여 보완

package se.magnus.my.app;

@SpringBootApplication
@ComponentScan({"se.magnus.myapp", "se.magnus.utill"})
public class MyApplication{
   

이제 애플리케이션 코드에 유틸리티 컴포넌트를 자동으로 주입

package se.magnus.utils;

@component
public class MyUtility{...

애플리케이션 컴포넌트를 다음과 같이 구성하면 앞의 유틸리티 컴포넌트가 자동 주입

package se.magnus.myapp.services;

public class AnotherComponent{
    private final MyUtility myUtility;

    @AutoWired
    public AnotherComponent(MyUtility myUtility){
        this.myUtility = myUtility;
    }

자바 기반 구성

◇ 스프링 부트의 기본 구성을 재정의 하거나 자체 구성을 추가하기 위해서는 @comfiguration 애노테이션 추가

public class SubscriberApplication{
    @Bean
    public Filter logFilter(){
        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setMaxPayloadLength(5120);
        return filter;
    }
}

HTTP 요청을 처리하는 부분에 필터를 삽입해 요청 처리 이전과 이후의 로그 메세지를 작성하는 경우 구성 샘플 코드


스프링 웹플럭스

 스프링 웹플럭스로 논블로킹 HTTP 클라이언트와 서비스의 개발을 지원
 스프링 웹플럭스가 지원하는 프로그래밍 모델
    ◆ 애노테이션 기반 명령형 방식 : 스프링 웹 MVC와 유사하지만 리액티브 서비스 지원
    ◆ 함수 지향 모델 기반의 라우터 및 핸들러 방식
◇ 서블릿 컨테이너(v3.1 이상 필요) 실행을 지원하며 내장형 리액티브 서버도 지원

REST 서비스 설정에 대한 코드 예제

먼저 스프링 웹플럭스와 필수 의존성을 스프링 부트 클래스패스에 추가하여 애플리케이션이 시작할 때 감지 및 구성하도록 해야함
◇ 스프링 부트는 특정 기능을 위한 다양한 스타터 의존성과 각 기능에 필요한 의존성을 함께 제공

스타터 의존성

그래들(gradle)을 빌드 도구로 사용하여 build.gradle 파일에 스타터 의존성을 추가

implementation('org.springframework.boot: spring-boot-starter-webflux')

속성 파일

포트 변경 : 속성 파일(application.propertis파일/application.YAML)을 사용해 기본값을 재정의

server.port:7001

샘플 RestController

내장형 웹 서버를 사용하더라도 RestController 기반의  REST 서비스를 만들 수 있음

 

@RestController
public class MyResetService{

    @GetMapping(value="/my-resource", produces = "application/json")
	List<Resource> listResources(){
 	...
	}

@GetMapping 애노테이션을 사용해 listResources() 메서드를 host:8080/resource URL에 연결된 HTTP GET API로 제작

List<Resource> 유형의 반환값은 JSON으로 변환


스프링 폭스

◇ 스프링 프레임워크와 별개의 오픈 소스 프로젝트로 런타임에 스웨거 기반의 API 문서를 생성함
◇ 문서 생성을 위해 웹플럭스, 스웨거 기반 애노테이션 등을 애플리케이션이 시작될 때 검사함
◇ 스프링프레임워크로 만든 마이크로서비스를 좀 더 쉽게 이해 할 수 있음


스프링 데이터

다양한 유형의 데이터 베이스 엔진에 데이터를 저장하기 위한 공통 프로그래밍 모델 제공
    ◆ 관계형 데이터베이스(SQL)
    ◆ 문서 데이터베이스(MongoDB)
    ◆ 키 값 데이터베이스(레디스)
    ◆ 그래프 데이터베이스(Neo4J) 등의 NoSQL 데이터베이스 엔진
 엔티티(entity)와 리포지토리(repository)를 통해 다양한 유형의 데이터베이스에 데이터를 저장하고 접근하는 방법을 일반화
◇ 스프링데이터는 엔티티와 리포지토리로 공통 추상화를 제공하며 특정 데이터 베이스를 위한 기능 추가도 지원

 

엔티티

◇ 스프링 데이터가 저장하는 데이터
◇ 보통 엔티티 클래스에는 일반 스프링 데이터 애노테이션과 데이터베이스 기술에 따른 애노테이션으 혼합해 사용

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;

public class ReviceEntity{
    @Entity
    @IdClass(ReviewEntitiyPK.class)
    @Table(name="review")
    private String author;
    private String subject;
    private String content;

}

◇ 엔티티를 MongoDB 데이터베이스에 저장하는 경우, MongoDB 하위 프로제그의 애노테이션과 일반 스프링 데이터 애노테이션을 함께 사용

import org.springframwork.data.annotation.Id;
import org.springframwork.data.annotation.Version;
import org.springframwork.data.mongodb.core.mapping.Document;

@Document
public class RecommendationEntity{

@Id
private String id;

@version
private int version;


private int productID;
private int recommendationId;
private int String author;
private int rate;
private String content;
}

 @Id, @Version 애노테이션은 일반 애노테이션
 @Document 애노테이션은 스프링 데이터 MongoDB 하위 프로젝트의 고유 애노테이션
◇ import 문으로 구별(import문에 mongodb문자열이 있으면 스프링 데이터 MongoDB에 속한 것)

리포지토리

◇ 여러 유형의 데이터베이스에 데이터를 저장하고 접근하고자 사용
◇ 대제 자바 인터페이스로 선언
◇ 스프링데이터가 상황에 따른 구현을 독자적인 규칙에 맞춰서 생성함
◇ 구성을 추가하여 구칙을 재정의하거나 보완 할 수 있으며 필요한 경우 약간의 자바 코드를 사용할 수 있음
◇ 스프링 데이터는 리포지토리를 간단히 정의 할 수 있도록 CrudRepository 등의 몇 가지 기본 자바 인터페이스 제공
     ◆ CrudRepository는 생성, 읽기, 업데이트 삭제 작업을 위한 표준 메서드 제공

 

JPA 엔티티인 ReviewEntity를 위한 리포지토리 선언

이 예제에서는 ReviewEmtityPK 클래스를 사용해 복합 기본키를 표현

import org.springframework.data.repository.CrudRepository;

public interface ReviewRepository extends CrudRepository<ReviewEntity, ReviewEntityPK>{
	Collection<ReviewEntity> findbyProductId(int productID);
}

ReviewEntityPK 클래스의 구현

public class ReviewEntityPK implements Serializable{
 public int productID;
 public int reviewID;
}

또한 findByProductId 메서드를 추가해 기본 키의 하나인 productID로 Review 엔티티를 조회
스프링 데이터가 정의한 이름 지정 규칙에 따라 메서드 이름을 지정하면 스프링 데이터가 이 메서드의 구현을 알아서 생성함
리포지토리를 사용하는 경우에는 리포지토리를 주입한 후 사용함

public final ReviewRepository repository;

@Autowired
public ReviewService(ReviewRepository repository){
	this.repository = repository;
}

public void someMethod(){
 repository.save(entity);
 repository.delete(entity);
 repository.findByProductId(productId);
}

 

ReactiveCrudRepository

리액티브 리포지토리를 만드는 리액티브 기반 인터페이스인 ReactiveCrudRepository를 제공
◇ 인터페이스의 메서드는 객체나 객체 집합을 반환하는 대신 Mono, Flux 객체를 반환
     ◆Mono, Flux 객체는 이용 가능한 스트림상의 0..1이나 0..m 엔티티를 반환하는 리액티드 스프림
◇ 리액티브 기반 인터페이스는 논블로킹 I/O 기반의 리액티브 데이터베이스 드라이버를 지원하는 스프링 데이터 하위 프로젝트에서만 사용
◇ 스프링 데이터 MongoDB의 하위 프로젝트는 리액티브 리포지토리를 지원하지만 스프링 데이터 JPA는 지원하지 않음

MongoDB 엔티티인 RecommendationEntity 리액티브 리포지토리 만들기

import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;

public interface RecommendationRepository extends ReactiveCrudRepository<RecommendationEntity, String>{
 Flux<RecommendationEntity> findByProductId(int productID)
}

스프링 클라우드 스트림

◇ 스프링 클라우드의 모듈 중 하나
 게시-구독 통합 패턴을 기반으로 하는 메시징 방식의 스트리밍 추상화를 제공
◇ 현재 아파치 카프카와 RabbitMQ를 기본 지원


스프링 클라우드 스트림의 핵심 개념

메시지(Message) : 메시징 시스템과 주고받는 데이터를 설명하는 데이터 구조
게시자(Pulbisher) : 메시징 시스템에 메시지를 보냄
구독자(Subscriber) : 메시징 시스템에서 메시지를 받음
채널(Channel) : 메시징 시스템과 통신하는데  사용. 출력 채널을 사용하고 구독자는 입력 채널을 사용
바인더(Binder) : 특정 메시징 시스템과의 통합 기능을 제공. JDBC 드라이버가 특정 데이터베이스를 지원하는 것과 유사
어떤 메시징 시스템을 사용할지는 런타임에 클래스패스를 검색한 결과에 따라 결정됨.

스프링 클라우드 스트림에는 메시징 처리 방법에 대한 독자적인 규칙이 있으며 메시징의 기능을 재정의 할 수 있음

스프링 클라우드 스트림을 사용한 메시지 송수신 예제

1.다음과 같은 메시지 클래스가 있다고 가정

public class MyMessage{
 private String attribute1 = null;
 private Stirng attribute2 = null;
}

 

2.메시지 게시 (기본 입력 채널과 출력 채널을 재공함으로, 직접 만들 필요 없이 메시지 게시가 가능)

import org.springframework.cloud.stream.messaging.Source;

@EnableBinding(Source.class)
public class MyPublisher{

@Autowired
private Source mysource;

	public String processMessage(MyMessage message){
	mysource.output().send(MessageBuilder.withPayload(message).build());
	}
}

3.메시지 수신

import org.springframework.cloud.stream.messaging.Sink;

public class MySubscriber{
	@StreamListener(target=Sink.INPUT)
	public void receive(Mymessage message){
    Log.info("Received:{}", message)
    }
}

4.RabbitMQ에 바인딩하고자 빌드 파일에 스타터 의존성 추가

implementation('org.springframework.cloud:spring-cloud-starter-stream-rabbit')


5.입력 채널과 출력 채널 구성(YAML 구성 파일을 사용하는 경우

//게시자 구성
spring.cloud.stream;
 default.contenType: application/json; //json형식으로 직렬화 되도록 형식 지정
 bindings.output.destination: mydestination;
 
//구독자 구성 
 spring.cloud.stream;
  default.contenType: application/json;
  bindings.input.destination: mydestination;
 

도커

◇ 2013년, 가상머신을 대체하는 경량 컨테이너 개념을 발표하고 일반화시킴
◇ 컨테이너는 리눅스 호스트에서 실행하며 네임스페이스를 이용해 사용자, 프로세스, 파일 시스템, 네트워킹 등의 전역 시스템 리소스를 컨테이너에 분배
◇ 리눅스 제어 그룹을 사용해 컨테이너가 사용 할 수 있는 CPU와 메모리를 제한함
◇ 컨테이너를 통해 공조 마이크로서비스 및 자원 관리자를 포함한 전체 시스템 환경을 단일 테스트를 위해 커멘드로 시작 할 수 있음
◇ 상용 환경에서 사용하기 위해 컨테이너 오케스트레이터(ex.쿠버네티스)가 필수임

 

Dockerfile을 사용한 도커 컨테이너 실행

FROM openjdk.12.0.2

MAINTAINER Magnus Larsson <magnus.larsson.ml@gmail.com>

EXPOSE 8080
ADD ./bulid/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]

도커 컴포즈를 통한 관리 컨테이너 설정

◇ build 옵션: 각 마이크로서비스에 사용할 Dockerfile을 지정함. 도커 컴포즈는 이 Dockerfile을 사용해 도커 이미지를 빌드 한 후 이 이미지를 사용해 도커 컨테이너를 시작
◇ ports 옵션: 도커를 실행하는 서버의 8080포트와 컨테이너의 8080 포트를 맵핑

product:
 build: microservices/product-service

recommendation:
 build: microservices/recommendation-service
 
review:
 build: microservices/review-service
 
composite:
 build: microservices/product-composite-service
 ports:
  - "8080:8080"

YAML 파일 컨테이너 관리하는 커맨드

docker-compose up -d: 모든 컨테이너 시작. 컨테이너를 백그라운드에서 실행하고 커맨드를 실행한 터미널을 잠그지 않고자 -d 스위치 사용
docker-compose down: 모든 컨테이너를 중지하고 제거

docker-compose logs -f --tail=0: 모든 컨테이너의 로그 메세지를 출력함. 커맨드를 종료하지 않고 새 로그 메시지를 기다리게 하고자 -f 스위치를 사용하며, 이전 로그 메시지는 생략하고 새 로그 메시지만 보고자 --tail=0 스위치를 사용

 


요약

- 공조 마이크로서비스 구축에 사용하는 스프링부트와 그 밖에 오픈 소스 도구를 소개함
- 스프링 부트를 사용하면 스프링 프레임워크와 서드파티 라이브러리의 핵심 모듈을 편하게 설정할 수 있어서 스프링 기반의 상용 애플리케이션을 쉽게 개발 할 수 있음 
- 스프링 웹플럭스는 새롭게 등장한 스프링 모듈로 리액티브, 즉 논블로킹 REST 서비스를 개발할 때 사용 할 수 있으며, 네티와 같은 령량 웹 서버와 서블릿 3.1+ 호환 웹 서버에서도 실행이 가능함. 또한 스프링 MVC 모듈의 프로그래밍 모델을 지원하므로 코드를 전부 재작성 하지 않아도 스프링 MVC용으로 만든 REST 서비스를 쉽게 웹플럭스용으로 만들 수 있음.
- 스프링 폭스는 스웨거와 OpenAPI 기반으로 REST서비스를 문서화 할 때 사용함. 런타임에 REST 서비스의 애노테이션을 조사해 즉시 문서들 생성함
- 스프링 데이터는 엔티티와 리포지토리로 영속 데이터에 접근하고 조작하기 위한 우아한 추상화를 제공함. 프로그래밍 모델이 유사하긴 하지만 여러 데이터베이스 유형 사이의 이식성은 없음.
- 스프링 클라우드 스트림은 게스-구독 통합 패턴을 기반으로 하는 메시징 방식의 스트리밍 추상화를 제공함. 아파치 카프카와  - RabbitMQ를 기본 지원하며 다른 메시징 브로커를 지원하도록 사용자 정의 바인더를 사용해 확장 가능.
- 도커는 가상머신을 대체하는 경량 컨테이너 도구. 컨테이너는 리눅스 네임스페이스와 제어 그룹을 기반으로 종래의 가상머신과 유사한 격리 기능을 제공하며, CPU와 메모리 사용 측면의 오버헤드를 크게 줄임. 도커는 개발과 테스트에 매우 유용한 도구이지만, 상용 환경에서 사용하려면 쿠버네티와 같은 오케스트레이터가 필요함.

'MSA' 카테고리의 다른 글

03장 공조 마이크로서비스 집합 생성  (0) 2021.04.07
01장 마이크로서비스 소개  (0) 2021.03.16

관련글 더보기

댓글 영역