1장에서는 마이크로서비스의 개요 및 아키텍처, 클라우드 개념 등에 대해서 알아보았습니다.
그럼 2장에서는 마이크로서비스를 스프링으로 구현하기 위한 스프링 부트에 대한 사전지식을 알아볼시다~
스프링 부트 소개
우선 마이크로서비스에서 표준 스프링 컨피규레이션이 아닌 스프링 부트를 사용하면 좋은 점과 스프링 부트의 장점을 알아보겠습니다.
스프링 부트는 표준 스프링 컨피규레이션과 다르게 독립 실행형 어플리케이션을 java -jar 명령어를 통해 실행합니다.
스프링 부트는 표준 스프링 컨피규레이션과 달리 웹 컨테이너를 애플리케이션에 포함할 수 있습니다.
마이크로서비스에서 표준 스프링 컨피규레이션보다 스프링 부트가 더 적합한 이유는 여기에 있습니다.
마이크로서비스는 다른 마이크로서비스와의 독립성이 중요합니다. 그러므로 데이터베이스와 웹 컨테이너와 같은 공통의 자원을 공유하지 않아야 합니다.
그러나 표준 스프링 컨피규레이션은 애플리케이션에 웹 컨테이너를 포함하는 대신 애플리케이션을 war 형태로 웹 컨테이너에 배포하므로,
하나의 웹 컨테이너에 여러 war 파일을 배포할 수 있기 때문에 마이크로서비스와는 적합하지 않습니다.
스프링 부트의 가장 큰 장점은 표준 스프링에 비해 간단하다는 것입니다.
스프링 부트가 간단할 수 있는 이유는 크게 두 가지인데,
그 두 가지는 스타터와 자동 컨피규레이션(auto-configuration) 입니다.
스타터는 프로젝트 의존성에 포함될 수 있는 아티팩트입니다. (여기서 아티팩트는 빌드로 생성되는 결과물을 이야기합니다.)
스타터는 필요한 의존성을 패키지로 제공해주므로 별도의 설정이 필요 없이 즉시 사용할 수 있어 매우 빠르고 간단합니다.
스타터의 공식적인 명명 패턴은 spring-boot-start-* 입니다.
자동 컨피규레이션은 스타터에 포함된 아티팩트의 기본 설정을 다른 속성이나 다른 유형의 스타터로 쉽게 재정의할 수 있게 해줍니다.
(추가된 의존성의 아티팩트 기반으로 스프링 애플리케이션을 자동적으로 설정해주며 다른 설정으로 변경할 수도 있다는 것을 말합니다.)
스프링 부트를 이용한 애플리케이션 개발
이제 스프링 부트를 이용하여 간단한 애플리케이션을 개발해보겠습니다.
스프링 부트와 메이븐(Maven)과 그래들(Gradle)과 같은 의존성 관리시스템을 활용하면 어떠한 의존성을 포함하는지 간단히 확인할 수 있어 매우 효율적입니다.
의존성 관리 도구를 통해 톰캣을 기본 컨테이너로 내장한 spring-boot-start-web (RESTful, Spring MVC 포함하는 기본 스타터)을 추가합니다.
다음은 메이븐 pom.xml 예제입니다.
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.7 RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> | cs |
또는 spring-boot-starter-parent POM에서 상속받지 않고 dependencyManagement 태그를 사용할 수도 있습니다.
[dependencyManagement 부연설명 : https://examples.javacodegeeks.com/enterprise-java/maven/use-maven-dependency-management-2/]
| <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.5.7.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> | cs |
그래들 입니다.
| plugins { id 'org.springframework.boot' version '1.5.7.RELEASE' } dependencies { compile("org.springframework.boot:spring-boot-stater-web:1.5.7.RELEASE") } | cs |
이제 Main 애플리케이션 클래스를 생성하고 @SpringBootApplication 애노테이션을 추가합니다.
@SpringBootApplication은 @Configuration, @EnableAutoConfiguration, @ComponentScan의 세 애노테이션과 같습니다.
| @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } | cs |
이제 실행 가능한 애플리케이션이 완성되었습니다.
그리고 모든 의존성을 포함하는 실행 가능한 JAR (팻JAR 또는 JARs)를 생성하기 위해서는
메이븐의 spring-boot-maven-plugin이 필요합니다. pom.xml에 추가해줍니다.
| <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>srping-boot-maven-plugin</artifactId> </plugin> </plugins> </build> | cs |
이제 기본 스프링 라이브러리를(spring-core, spring-aop, spring-context, spring boot, 내장형 톰캣, 로깅 라이브러리 등) 포함한 팻JAR를 생성할 수 있습니다.
컨피규레이션 파일 사용자 정의하기
스프링 부트는 편리하고 쉽게 설정을 관리할 수 있는 메커니즘을 제공합니다.
가장 간단한 방법은 애플리케이션 JAR에 추가된 컨피규레이션 파일을 이용하는 것입니다.
스프링 부트는 application으로 시작하는 컨피규레이션 파일을 자동으로 찾으며, 지원하는 파일 타입은 .properties와 .yml입니다.
(설정 파일명은 일반적으로 application 또는 application-{profile}이며 이외의 특정한 이름을 부여하려면 환경변수를 통해 등록 가능합니다.)
또한 컨피규레이션 파일을 외부로 뽑아낼 수 있는데, 이 때 파일의 위치는 다음과 같아야 합니다.
- 애플리케이션의 현재 디렉토리의 /config 하위 디렉터리
- 애플리케이션의 현재 디렉토리
- 클래스 경로 /config 패키지
- 클래스 경로 root
일반적으로 application 컨피규레이션 파일은 src/main/resources 디렉토리에 위치하며, 메이븐 빌드 후에는 JAR의 루트에 위치합니다.
컨피규레이션 파일에서 두 종류의 설정을 지정할 수 있습니다. 첫 번째는 주로 spring-boot-autoconfiguration 라이브러리에서 사용되는 공통설정과 미리 정의된 스프링 부트 설정입니다. 두 번째는 사용자 정의 속성을 지정할 수 있으며 @Value 또는 @ConfigurationProperties 애노테이션을 통해 주입될 수 있습니다.
기본 서버 포트, 애플리케이션 이름, 로깅 속성 등을 재정의하는 예제 .yml 컨피규레이션 파일을 작성해봅시다.
| server : port : ${port:2222} spring : application : name : first-service logging : pattern : console : "%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" file : "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" level : org.springframework.web : DEBUG file : app.log | cs |
외부 컨피규레이션 파일을 지정할 필요 없이 간단하게 설정을 할 수 있습니다. 로깅 컨피규레이션을 위해 log4j.xml 또는 logback.xml 등을 설정할 필요가 없다는 말입니다. 기본 로그 레벨을 DEBUG로 변경하고 로그 패턴을 수정하고 app.log 파일을 생성했으며, 기본 HTTP 포트는 2222라는 설정을 간단하게 하였습니다.
사용자 컨피규레이션도 같은 파일에 위치해야 한다. 사용자 정의 속성을 포함하는 예제를 작성해봅시다.
| name : first-service my : service : -dev.bar.com -foo.bar.com | cs |
위와 같이 설정 후 @Value, @ConfigurationProperties 애노테이션을 활용해 주입할 수 있습니다.
| @Component public class CustomBean { @Value("${name}") private String name; // ... } @ConfigurationProperties(prefix="my") public class Config { private List<String> servers = new ArrayList<>(); public List<String getServers() { return this.servers; } } | cs |
지금까지 간단한 애플리케이션을 설정하고 생성했습니다. 이와 다른 방법으로 웹에서 생성하는 방법도 존재합니다.
스프링 이니셜라이즈 웹사이트(https://start.spring.io)를 통해서도 프로젝트를 생성할 수 있습니다.
RESTful 웹서비스 생성하기
이제 RESTful 웹서비스를 만들어봅시다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @RestController @RequestMapping("/person") public class PersonController { @GetMapping public List<Person> findAll() { return getPersons(); } @GetMapping("/id") Person findById(@RequestParam("id") Long id) { return getPerson(id); } @PostMapping Person add(@RequestBody Person p) { p.setId(getPersons().size() + 1); addPerson(p); return p; } @DeleteMapping("/{id}") public void delete(@RequestParam("id") Long id) { removePerson(id); } @PutMapping("/{id}") public void update(@RequestBody Person p) { updatePerson(p); } } | cs |
@RestController는 HTTP 요청을 처리하는 컨트롤러 빈 클래스에 설정하면 RESTful 웹서비스를 지원합니다.
@RequestMapping은 컨트롤러 메소드와 HTTP URL 주소를 대응해줍니다.
@GetMapping, @PostMapping, @DeleteMapping, @PutMapping은 특정 HTTP 메서드를 지정해 주며 @RequestMapping(method=RequestMethod.GET)과 동일합니다.
@RequsetParam은 요청의 경로와 입력값을 객체로 바인딩한다.
@RequestBody는 입력 JSON을 잭슨 라이브러리를 사용해 객체로 바인딩한다.
자 이제 우리는 몇 개의 REST API를 제공하는 첫 마이크로서비스를 만들었습니다.
그렇다면 다른 클라이언트가 이 API를 호출하기 위해서는 API 문서가 필요합니다.
여기서 스웨거(Swagger)가 필요합니다. 스웨거는 API문서를 제공하고 자동으로 생성해주는 도구입니다.
API 문서화
스웨거는 RESTful API를 설계하고 빌드하고 문서화하는데 가장 많이 사용되는 도구입니다.
스웨거를 통해 API를 설계하고 소스코드를 생성할 수 있고, 소스코드로 API 문서인 스웨거 파일을 생성할 수 있습니다.
스웨거2를 스프링 부트와 같이 사용하기
스프링 부트와 스웨거2는 스프링폭스(Springfox) 프로젝트에 구현되어 있습니다.
스웨거를 사용하기 위해 의존성을 추가하고 Main 애플리케이션에 @EnableSwagger2 애노테이션과 Docket 빈을 추가합니다.
| <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.7.0</version> </dependency> | cs |
| @Bean public Docket api() throws IOException, XMLPullParserConfiguration { MavneXpp3Reader reader = new MavenXpp3Reader(); Model model = reader.read(new FileReader("pom.xml")); ApiInfoBuilder builder = new ApiInfoBuilder() .title("Person Service Api Documentation") .description("Documentation automatically generated") .version(model.getVersion()) .contact(new Contact("Piotr Minkowski", "piotrminkowski.wordpress.com", "hyyg123@gmail.com")); return new Docket(DocumentationType.SWAGGER_2).select() .apis(RequestHandlerSelectors.basePacakge("pl.pimin.services.boot.controller")) .paths(PathSelectors.any()).build() .apiInfo(builder.build()); } | cs |
애플리케이션이 시작될 때 스웨거에 의해 API 문서가 자동으로 생성됩니다.
API 문서 대시보드는 /swagger-ui.html 에서 확인할 수 있습니다.
이러한 것들은 Main에 등록된 Docket 빈에 의해 처리되며,
APi의 타이틀, 저자, 설명 같은 속성을 설정할 수 있습니다. 또한 패키지 별로 설정이 가능합니다. (예제에서는 pl.pimin.services.boot.controller)
스웨거 UI를 통한 API 테스트
또한 스웨거 UI를 통해서 포스트맨(API 테스트 도구)과 유사하게 API 테스트를 할 수 있습니다. 자세한 내용은 생략하겠습니다.
스프링 부트 액추에이터의 기능
마이크로서비스에서는 애플리케이션의 모니터링과 메트릭 수집이 중요합니다.
이를 위해 스프링 부트에서는 스프링 부트 액추에이터를 지원합니다.
스프링 부트 액추에이터는 모니터링과 상호작요을 하기 위한 내장된 수 많은 API를 제공합니다.
스프링 부트 액추에이터를 사용하기 위해서는 spring-boot=starter-actuator 의존성을 추가해야 합니다.
다음은 몇 개의 API 목록입니다.
- /beans - 모든 스프링 빈의 목록을 표시
- /health - 상태 정보 표시
- /info - 애플리케이션 임의 정보 표시 (예를 들어 build-info.properties나 git.properties 파일 정보 표시)
- /loggers - 로거 정보 표시
- /metrics - 메모리 사용량, 실행 중인 스레드 수, RST 메서드의 응답 시간 등의 메트릭 정보를 표시
비활성화 방법은 application.yml에 다음과 같이 추가합니다.
| management : security : enabled : false | cs |
애플리케이션 정보
/info API를 통해 호출합니다. 기본적으로 어떤 정보도 노출하지 않으므로 InfoContributer 빈을 변경하거나 자신만의 빈을 작성해야 합니다.
EnvironmentInfoContributor는 환경 정보를 노출합니다.
GitInfoContributor는 git.properties를 통해 브랜치 이름이나 커밋ID와 같은 커밋 정보를 노출합니다.
(git-commit-id-plugin을 pom.xml에 추가해야 합니다.)
BuildInfoGontributor는 META-INF/build-info.properties 정보를 통해 API를 노출합니다.
(spring-bood-maven-plugin을 수정해 build-info.properties를 자동 생성하도록 해야 합니다.)
상태 정보
/health API를 통해 호출합니다.
디스크 사용량, 메일 서비스, JMS, 데이터 소스, 몽고디비 또는 카산드라와 같은 NoSQL 등을 모니터링 할 수 있습니다.
매트릭스
/metrics API를 통해 호출합니다.
로딩된 클래스의 개수, 활성화된 스레드의 수, API 메서드의 평균 실행 시간 등을 표시합니다.
CountService와 GaugeService를 통해 자신만의 메트릭을 생성할 수 있습니다.
CountService는 값의 증가와 감소, 초기화를 위한 메서드를 제공합니다.
GaugeService는 단순히 현재의 값을 전달하는 메서드를 제공합니다.
모든 메트릭은 분석하거나 표시할 수 있는 저장소로 전달이 가능합니다.
레디스(Redis), Open TSDB, Statsd, 인플럭스디비 등에 저장하여 활용할 수 있습니다.
이러한 문서화, 메트릭, 상태 점검은 마이크로서비스를 개발하고 유지보수하는데 매우 중요한 역할을 합니다.
개발자 도구
spring-boot-devtools 의존성을 추가하면, 소스 파일 변경사항을 감지하여 자동으로 반영해줍니다. (마치 jrebel과 비슷하게 작동합니다.)