본문 바로가기

Spring/Spring.io

Guide - 스프링 부트를 이용한 애플리케이션 빌드

 

https://spring.io/guides/gs/spring-boot

 

 

Spring Boot 기능
클래스패스에 따라 필요한 설정을 자동으로 구성

 

  • 코드 생성, 수정 없이 애플리케이션 실행 시점에 동적으로 빈과 설정을 연결
    • Spring MVC가 클래스 패스에 있으면 필요한 빈들을 자동으로 추가하고 서블릿 컨테이너가 필요하므로 자동으로 Tomcat을 서버로 사용
    • Jetty가 클래스 패스에 있으면 자동으로 Tomcat 대신에 Jetty를 서버로 사용
  • 인프라 설정에 대한 부담 감소
  • 개발자가 직접 정의한 빈 우선

 

프로젝트 초기화

 

  1. https://start.spring.io 접속
  2. 빌드 도구, 언어, 스프링 부트 버전 선택
  3. Dependecies 추가
  4. Generate 클릭 후 zip 파일 다운로드

- 설정 예시

 

컨트롤러 생성

 

// src/main/java/com/example/springboot/HelloController.java

package com.example.springboot;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/")
    public String index() {
        return "Greetings from Spring Boot!";
    }
}

 

  • @RestController = @Controller + @ResponseBody -> 요청에 대해 view가 아닌 data를 반환
  • @GetMapping : '/' 로 오는 Get 요청을 index() 메서드에 매핑

 

Application 클래스 생성

 

// src/main/java/com/example/springboot/Application.java
// 기본으로 생성되는 application을 수정(애플리케이션 컨텍스트에서 관리하는 모든 빈 출력)

package com.example.springboot;

import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

	@Bean
	public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
		return args -> {
			System.out.println("Let's inspect the beans provided by Spring Boot :");

			String[] beanNames = ctx.getBeanDefinitionNames();
			Arrays.sort(beanNames);
			for (String beanName : beanNames) {
				System.out.println(beanName);
			}
		};
	}
}

 

  • @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
    • @Configuration : 애플리케이션 컨텍스트에서 빈을 정의하는 클래스
    • @ EnableAutoConfiguration : 클래스 패스 설정, 다른 빈, 속성 설정을 기반으로 자동으로 빈 추가
    • @ComponentScan : 패키지 내에서 컴포넌트, 설정, 서비스 등을 자동으로 검색
  • main() 메서드는 Spring Boot의 SpringApplication.run() 메서드로 애플리케이션 실행
    • XML 설정 없는 100% 자바 코드
  • CommandLineRunner : 애플리케이션이 실행될 때 실행되는 코드 블록 정의

 

애플리케이션 실행
  • window terminal에 ./gradlew bootRun 입력
    • Spring Boot의 자동 설정 빈 출력(org.springframework.boot.autoconfigure)
    • 내장 톰캣 설정 빈 출력(TomcatServletWebServerFactory )
    • 그 외 애플리케이션 컨텍스트에서 관리하는 다양한 빈 확인 가능
  • 다른 window terminal에서 curl http://localhost:8080 입력
$ curl http://localhost:8080
Greetings from Spring Boot!

 

단위 테스트 추가

 

// src/test/java/com/example/springboot/HelloControllerTest.java
// MockMvc

package com.example.springboot;

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}

 

  • @SpringBootTest : 애플리케이션 전체 컨텍스트(컨트롤러, 서비스, 리포지토리 등) 생성
    • @WebMvcTest : 웹 계층(컨트롤러, 관련 설정 등)만 로드
  • @AutoConfigureMockMvc : MockMvc 인스턴스 주입
// src/test/java/com/example/springboot/HelloControllerITest.java
// TestRestTemplate

package com.example.springboot;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.ResponseEntity;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerITest {

    @Autowired
    private TestRestTemplate template;

    @Test
    public void getHello() throws Exception {
        ResponseEntity<String> response = template.getForEntity("/", String.class);
        assertThat(response.getBody()).isEqualTo("Greetings from Spring Boot!");
    }
}
  • webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT : 내장 서버는 랜덤 포트에서 시작
  • 실제 포트는 TestRestTemplate의 기본 URL에 자동으로 설정

 

테스트 방식 MockMvc TestRestTemplate
웹 서버 실행 실제 서버 실행 안함 내장 서버 실행
요청 방식 DispatcherServlet 직접 호출 실제 HTTP 요청 발생
테스트 유형 단위 테스트 통합 테스트
적용 범위 컨트롤러 계층만 테스트 전체 애플리케이션 테스트

 

운영 환경 관리 서비스 추가

 

1. build.gradle의 dependencies에 의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-actuator'

 

2. 서버 재실행(window terminal에 ./gradlew bootRun 입력)
3. Spring Boot에서 제공하는 관리 서비스(management. 으로 시작) 확인 가능

4. 헬스 체크

$ curl http://localhost:8080/actuator/health
{"status":"UP"}

 5. shutdown 엔드포인트 호출

$ curl -X POST http://localhost:8080/actuator/shutdown
{"timestamp":1401820343710,"error":"Not Found","status":404,"message":"","path":"/actuator/shutdown"}

 

 - 아래와 같은 설정을 application.properties에 추가하여 shutdown 엔드포인트를 활성화할 수 있지만 공개된 어플리케이션에서는 활성화하지 않는 것을 권장

management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=health,info,shutdown

 

Spring Boot Loader 모듈
spring-boot-gradle-plugin 및 spring-boot-maven-plugin 사용하여 WAR 파일 배포, 실행 가능한 JAR 파일 생성 지원