6. Developing with Spring Boot
이번 장에서는 스프링 부트를 사용하는 방법에 대해 자세히 설명한다. 빌드 시스템, 자동 구성(auto-configuration), 애플리케이션 실행 방법 등의 주제를 다룬다. 또한 몇 가지 스프링 부트 모범 사례도 다룬다. 스프링 부트에는 특별한 것은 없지만(사용할 수 있는 또 다른 라이브러리일 뿐이다), 개발 프로세스를 좀 더 쉽게 만들어 주는 몇 가지 권장 사항이 있다.
스프링 부트를 이제 막 시작하는 경우 시작하기 가이드를 먼저 읽어야 한다.
6.1. Build Systems
의존성 관리를 지원하고 “메이븐 센트럴” 저장소(repository)에 게시된 아티팩트를 사용할 수 있는 빌드 시스템을 선택하는 것이 좋다. 메이븐이나 그레이들을 선택하는 것이 좋다. 스프링 부트가 다른 빌드 시스템(예: 앤트(Ant))과 작동하도록 하는 것이 가능하지만 특별히 잘 지원되지는 않는다.
6.1.1. Dependency Management
스프링 부트의 각 릴리스는 지원하는 의존성 목록을 제공한다. 실제로는 스프링 부트가 이를 관리하므로 빌드 구성에서 의존성 라이브러이의 버전을 제공할 필요가 없다. 스프링 부트 자체를 업그레이드하면 이러한 의존성도 일관된 방식으로 업그레이드된다.
필요한 경우 버전을 지정하고 스프링 부트 의존성 라이브러리의 권장 버전을 오버라이드 할 수 있다.
큐레이트된(curated) 목록에는 스프링 부트와 함께 사용할 수 있는 모든 스프링 모듈과 서드파티 라이브러리 목록이 포함되어 있다. 이 목록은 메이븐과 그레이들 모두에서 사용할 수 있는 표준 BOM(spring-boot-dependent
)으로 제공된다.
스프링 부트의 각 릴리스는 스프링 프레임워크의 버전과 연관되어 있다. 해당 버전은 지정하지 않는 것이 좋다.
6.1.2. Maven
메이븐과 함께 스프링 부트를 사용하는 방법을 알아보려면, 스프링 부트의 메이븐 플러그인 설명서를 참고하자:
6.1.3. Gradle
그레이들과 함께 스프링 부트를 사용하는 방법을 알아보려면, 스프링 부트의 그레이들 플러그인 설명서를 참고하자:
6.1.4. Ant
아파치 앤트+아이비를 사용하여 스프링 부트 프로젝트를 빌드할 수 있다. spring-boot-antlib
“AntLib” 모듈은 앤트가 실행 가능한 jar를 생성하는 데 도움을 주기도 한다. 의존성을 선언하기 위한 일반적인 ivy.xml
파일은 다음 예와 같다:
<ivy-module version="2.0">
<info organisation="org.springframework.boot" module="spring-boot-sample-ant" />
<configurations>
<conf name="compile" description="everything needed to compile this module" />
<conf name="runtime" extends="compile" description="everything needed to run this module" />
</configurations>
<dependencies>
<dependency org="org.springframework.boot" name="spring-boot-starter" rev="${spring-boot.version}" conf="compile" />
</dependencies>
</ivy-module>
일반적인 build.xml
은 다음 예와 같다:
<project
xmlns:ivy="antlib:org.apache.ivy.ant"
xmlns:spring-boot="antlib:org.springframework.boot.ant"
name="myapp" default="build">
<property name="spring-boot.version" value="3.1.1" />
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve pattern="lib/[conf]/[artifact]-[type]-[revision].[ext]" />
</target>
<target name="classpaths" depends="resolve">
<path id="compile.classpath">
<fileset dir="lib/compile" includes="*.jar" />
</path>
</target>
<target name="init" depends="classpaths">
<mkdir dir="build/classes" />
</target>
<target name="compile" depends="init" description="compile">
<javac srcdir="src/main/java" destdir="build/classes" classpathref="compile.classpath" />
</target>
<target name="build" depends="compile">
<spring-boot:exejar destfile="build/myapp.jar" classes="build/classes">
<spring-boot:lib>
<fileset dir="lib/runtime" />
</spring-boot:lib>
</spring-boot:exejar>
</target>
</project>
spring-boot-antlib
모듈을 사용하지 않으려면 앤트에서 실행 가능한 압축파일 구축 “How-to”를 참고하자.
6.1.5. Starters
스타터는 애플리케이션에 포함할 수 있는 편리한 의존성 세트이다. 샘플 코드를 검색하고 많은 의존성 라이브러리을 복사하여 붙여넣을 필요 없이 모든 스프링 및 관련 기술에 대한 설정을 원스톱으로 얻을 수 있다. 예를 들어, 데이터베이스 접근를 위해 스프링 및 JPA를 사용하여 시작하려면 프로젝트에 spring-boot-starter-data-jpa
의존성을 포함할 수 있다.
스타터에는 프로젝트를 신속하게 시작하고 실행하는 데 필요한 많은 의존성이 포함되어 있으며, 일관되게 지원되는 관리형 전이적 의존성(managed transitive dependencies) 세트가 포함되어 있다.
What is in a name
모든 공식 스타터는 비슷한 명명 패턴을 따른다.
spring-boot-starter-*
, 여기서*
는 특정 타입의 애플리케이션이다. 이 명명 구조는 스타터를 찾아야 할 때 도움을 주기 위한 것입니다. 많은 IDE의 메이븐 통합을 통해 명칭으로 의존성을 검색할 수 있다. 예를 들어 이클립스 또는 스프링 툴 플러그인이 설치된 경우 POM 편집기에서ctrl-space
를 누르고 “spring-boot-starter”를 입력하면 전체 목록을 볼 수 있다.
“자신만의 스타터 만들기” 절에 설명된 대로 서드 파티 스타터는 공식 스프링 부트 아티팩트용으로 예약되어 있으므로
spring-boot
로 시작해서는 안 된다. 오히려 서드파티 스타터는 일반적으로 프로젝트 이름으로 시작한다. 예를 들어thirdpartyproject
라는 서드파티 스타터 프로젝트명은 일반적으로thirdpartyproject-spring-boot-starter
이다.
다음 애플리케이션 스타터는 스프링 부트의 org.springframework.boot
그룹으로 제공된다:
테이블 1. 스프링 부트 애플리케이션 스타터
명칭 | 설명 |
---|---|
spring-boot-starter | 자동 구성 지원, 로깅 및 YAML을 포함한 핵심 스타터 |
spring-boot-starter-activemq | 아파치 액티브MQ(ActiveMQ)를 사용하는 JMS 메시징용 스타터 |
spring-boot-starter-amqp | 스프링 AMQP 및 래빗(Rabbit) MQ 사용을 위한 스타터 |
spring-boot-starter-aop | 스프링 AOP 및 애스펙트J(AspectJ)를 사용한 관점 지향 프로그래밍을 위한 스타터 |
spring-boot-starter-artemis | 아파치 아르테미스(Artemis)를 사용하는 JMS 메시징용 스타터 |
spring-boot-starter-batch | 스프링 배치를 사용하기 위한 스타터 |
spring-boot-starter-cache | 스프링 프레임워크의 캐싱 지원을 사용하기 위한 스타터 |
spring-boot-starter-data-cassandra | 카산드라 분산 데이터베이스 및 스프링 데이터 카산드라 사용을 위한 스타터 |
spring-boot-starter-data-cassandra-reactive | 카산드라 분산 데이터베이스 및 스프링 데이터 카산드라 리액티브를 사용하기 위한 스타터 |
spring-boot-starter-data-couchbase | 카우치베이스(Couchbase) 도큐먼트 중심 데이터베이스와 스프링 데이터 카우치베이스를 사용하기 위한 스타터 |
spring-boot-starter-data-couchbase-reactive | 카우치베이스(Couchbase) 도큐먼트 중심 데이터베이스와 스프링 데이터 카우치베이스 리액티브를 사용하기 위한 스타터 |
spring-boot-starter-data-elasticsearch | 엘라스틱 서치 및 분석 엔진과 스프링 데이터 엘라스틱 서치를 사용하기 위한 스타터 |
spring-boot-starter-data-jdbc | 스프링 데이터 JDBC 사용을 위한 스타터 |
spring-boot-starter-data-jpa | 하이버네이트와 함께 스프링 데이터 JPA를 사용하기 위한 스타터 |
spring-boot-starter-data-ldap | 스프링 데이터 LDAP 사용을 위한 스타터 |
spring-boot-starter-data-mongodb | 몽고DB 도큐먼트 지향 데이터베이스와 스프링 데이터 몽고DB를 사용하기 위한 스타터 |
spring-boot-starter-data-mongodb-reactive | 몽고DB 도큐먼트 지향 데이터베이스와 스프링 데이터 몽고DB 리액티브를 사용하기 위한 스타터 |
spring-boot-starter-data-neo4j | 네오4j 그래프 데이터베이스와 스프링 데이터 네오4j를 사용하기 위한 스타터 |
spring-boot-starter-data-r2dbc | 스프링 데이터 R2DBC 사용을 위한 스타터 |
spring-boot-starter-data-redis | 스프링 데이터 레디스 및 레터스(Lettuce) 클라이언트와 함께 레디스 키-값 데이터 스토어를 사용하기 위한 스타터 |
spring-boot-starter-data-redis-reactive | 스프링 데이터 레디스 리액티브 및 레터스(Lettuce) 클라이언트와 함께 레디스 키-값 데이터 스토어를 사용하기 위한 스타터 |
spring-boot-starter-data-rest | 스프링 데이터 REST 및 스프링 MVC를 사용하여 REST를 통해 스프링 데이터 리포지터리를 노출하기 위한 스타터 |
spring-boot-starter-freemarker | 프리메이커(FreeMarker) 뷰를 사용하여 MVC 웹 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-graphql | 스프링 그래프QL(GraphQL)을 사용하여 그래프QL 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-groovy-templates | 그루비 템플릿 뷰를 사용하여 MVC 웹 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-hateoas | 스프링 MVC 및 스프리 HATEOAS를 사용하여 하이퍼미디어 기반 RESTful 웹 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-integration | 스프링 인테그레이션 사용을 위한 스타터 |
spring-boot-starter-jdbc | 히카리CP(HikariCP) 커넥션 풀과 함께 JDBC를 사용하기 위한 스타터 |
spring-boot-starter-jersey | JAX-RS 및 저지(Jersey)를 사용하여 RESTful 웹 애플리케이션을 구축하기 위한 스타터. spring-boot-starter-web 의 대안이다. |
spring-boot-starter-jooq | jOOQ 를 사용하여 JDBC로 SQL 데이터베이스에 접근하기 위한 스타터. spring-boot-starter-data-jpa 또는 spring-boot-starter-jdbc 의 대안이다. |
spring-boot-starter-json | json을 읽고 쓰기 위한 스타터 |
spring-boot-starter-mail | 자바 메일 및 스프링 프레임워크의 이메일 전송 지원을 사용하기 위한 스타터 |
spring-boot-starter-mustache | 머스태치(Mustache) 뷰를 사용하여 웹 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-oauth2-authorization-server | 스프링 Authorization 서버 기능을 사용하기 위한 스타터 |
spring-boot-starter-oauth2-client | 스프링 시큐리티의 OAuth2/OpenID Connect 클라이언트 기능을 사용하기 위한 스타터 |
spring-boot-starter-oauth2-resource-server | 스프링 시큐리티의 OAuth2 리소스 서버 기능을 사용하기 위한 스타터 |
spring-boot-starter-quartz | 쿼츠(Quartz) 스케줄러 사용을 위한 스타터 |
spring-boot-starter-rsocket | RSocket 클라이언트 및 서버 구축을 위한 스타터 |
spring-boot-starter-security | 스프링 시큐리티 사용을 위한 스타터 |
spring-boot-starter-test | JUnit 주피터(Jupiter), 햄크레스트(Hamcrest) 및 모키토(Mockito)를 포함한 라이브러리를 사용하여 스프링 부트 애플리케이션을 테스트하기 위한 스타터 |
spring-boot-starter-thymeleaf | Thymeleaf 뷰를 사용하여 MVC 웹 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-validation | 하이버네이트 밸리데이터(Validator)와 함께 자바 빈(Bean) 밸리데이터를 사용하기 위한 스타터 |
spring-boot-starter-web | 스프링 MVC를 사용하여 RESTful, 애플리케이션을 포함한 웹 구축을 위한 스타터. 톰캣을 기본 내장 컨테이너로 사용한다. |
spring-boot-starter-web-services | 스프링 웹 서비스 사용을 위한 스타터 |
spring-boot-starter-webflux | 스프링 프레임워크의 리액티브 웹 지원을 사용하여 웹플럭스(WebFlux) 애플리케이션을 구축하기 위한 스타터 |
spring-boot-starter-websocket | 스프링 프레임워크의 MVC 웹소켓(WebSocket) 지원을 사용하여 웹소켓t 애플리케이션을 구축하기 위한 스타터 |
애플리케이션 스타터 외에도, 다음 스타터를 사용하여 프로덕션 준비 기능을 추가할 수 있다:
테이블 2. 스프링 부트 프로덕션 스타터
명칭 | 설명 |
---|---|
spring-boot-starter-actuator | 애플리케이션을 모니터링하고 관리하는 데 도움이 되는 프로덕션 준비 기능을 제공하는 스프링 부트의 액추에이터(Actuator)를 사용하기 위한 스타터 |
마지막으로, 스프링 부트에는 특정 기술 측면을 제외하거나 교체하려는 경우 사용할 수 있는 다음 스타터도 있다:
테이블 3. 스프링 부트 기술 스타터
명칭 | 설명 |
---|---|
spring-boot-starter-jetty | 제티(Jetty)를 임베디드 서블릿 컨테이너로 사용하기 위한 스타터. spring-boot-starter-tomcat 의 대안이다. |
spring-boot-starter-log4j2 | 로깅을 위해 Log4j2를 사용하기 위한 스타터. spring-boot-starter-logging 의 대안 |
spring-boot-starter-logging | 로그백(Logback)을 사용하는 로깅을 위한 스타터. 기본(Default) 로깅 스타터 |
spring-boot-starter-reactor-netty | 리액터 네티를 내장된 반응형 HTTP 서버로 사용하기 위한 스타터 |
spring-boot-starter-tomcat | 톰캣을 내장 서블릿 컨테이너로 사용하기 위한 스타터. spring-boot-starter-web 에서 사용되는 기본 서블릿 컨테이너 스타터 |
spring-boot-starter-undertow | 언더토우를 임베디드 서블릿 컨테이너로 사용하기 위한 스타터. spring-boot-starter-tomcat 의 대안 |
기술적 측면을 교체하는 방법을 알아보려면, 웹 서버 교체 및 로깅 시스템 교체에 대한 방법 문서를 참고하자.
추가 커뮤니티 기여 스타터 목록은 깃헙의
spring-boot-starters
모듈에 있는 README 파일을 참고하자.
6.2. Structuring Your Code
스프링 부트는 작동하기 위해 특정 코드 레이아웃이 필요하지 않다. 그러나 도움이 되는 몇 가지 모범 사례가 있다.
6.2.1. Using the “default” Package
클래스에 패키지 선언이 포함되어 있지 않으면, “기본 패키지(default package)”에 있는 것으로 간주된다. “기본 패키지”의 사용은 일반적으로 권장되지 않으며 피해야 한다. 모든 jar의 모든 클래스를 읽기 때문에 @ComponentScan
, @ConfigurationPropertiesScan
, @EntityScan
또는 @SpringBootApplication
어노테이션을 사용하는 스프링 부트 애플리케이션에 특정 문제가 발생할 수 있다.
자바에서 권장하는 패키지 명명 규칙을 따르고 역방향 도메인 이름(예: com.example.project)을 사용하는 것이 좋다.
6.2.2. Locating the Main Application Class
일반적으로 기본 애플리케이션 클래스를 다른 클래스 위의 루트 패키지에 배치하는 것이 좋다. @SpringBootApplication
어노테이션은 Main
클래스에 배치되는 경우가 많으며 특정 항목에 대한 기본 “검색 패키지”를 암시적으로 정의한다. 예를 들어 JPA 애플리케이션을 구축하는 경우 @SpringBootApplication
어노테이션이 달린 클래스 패키지는 @Entity
항목을 검색하는 데 사용된다. 루트 패키지를 사용하면 컴포넌트 스캔을 일부 프로젝트에만 적용할 수도 있다.
@SpringBootApplication
을 사용하지 않으려면, 가져오는@EnableAutoConfiguration
및@ComponentScan
어노테이션이 해당 동작을 정의하므로 이를 대신 사용할 수도 있다.
다음 목록은 일반적인 레이아웃을 보여준다:
com
+- example
+- myapplication
+- MyApplication.java
|
+- customer
| +- Customer.java
| +- CustomerController.java
| +- CustomerService.java
| +- CustomerRepository.java
|
+- order
+- Order.java
+- OrderController.java
+- OrderService.java
+- OrderRepository.java
MyApplication.java
파일은 @SpringBootApplication
과 함께 main 메소드를 다음과 같이 선언한다:
자바
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
코틀린
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
6.3. Configuration Classes
스프링 부트는 자바 기반 구성을 선호한다. XML과 함께 SpringApplication
을 사용하는 것이 가능하지만, 코드가 @Configuration
클래스인 것이 좋다. 일반적으로 main
메소드를 정의하는 클래스는 @Configuration
으로 좋은 후보다.
XML을 사용하는 많은 스프링 구성 예제가 인터넷에 있다. 가능하다면 항상 자바 기반 구성을 사용하자.
Enable*
어노테이션을 검색하는 것이 좋은 시작점이 될 수 있다.
6.3.1. Importing Additional Configuration Classes
모든 @Configuration
을 싱글 클래스에 넣을 필요는 없다. @Import
어노테이션을 사용하여 추가 구성 클래스를 가져올 수 있다. 또는 @ComponentScan
을 사용하여 @Configuration
클래스를 포함한 모든 스프링 컴포넌트를 자동으로 선택할 수 있다.
6.3.2. Importing XML Configuration
반드시 XML을 사용해야 하는 경우에도 @Configuration
클래스로 시작하는 것이 좋다. 그런 다음 @ImportResource
어노테이션을 사용하여 XML 구성 파일을 로드할 수 있다.
6.4. Auto-configuration
스프링 자동 구성(auto-configuration)은 추가한 jar 의존성을 기반으로 스프링 애플리케이션을 구성한다. 예를 들어, HSQLDB가 클래스패스에 있고 데이터베이스 커넥션 빈(Bean)을 수동으로 입력하지 않은 경우 스프링 부트는 인메모리 데이터베이스를 자동으로 구성한다.
@Configuration
클래스 중 하나에 @EnableAutoConfiguration
또는 @SpringBootApplication
어노테이션을 추가하여 자동 구성을 선택해야 한다.
@SpringBootApplication
또는@EnableAutoConfiguration
어노테이션은 하나만 추가해야 한다. 일반적으로@Configuration
클래스에만 둘 중 하나를 추가하는 것이 좋다.
6.4.1. Gradually Replacing Auto-configuration
자동 구성(Auto-configuration)은 비침투적(non-invasive)이다. 언제든지, 자동 구성의 특정 부분을 대체하기 위한 자체 구성을 정의할 수 있다. 예를 들어, 자신만의 데이터소스 빈(DataSource Bean)을 추가하면 임베디드 데이터베이스 지원이 중단된다.
현재 적용되고 있는 자동 구성과 그 이유를 알아내려면 –debug 스위치를 사용하여 애플리케이션을 시작해보자. 이렇게 하면 선택한 코어 로거(logger)에 대한 디버그 로그가 활성화되고 상태 보고서가 콘솔에 기록된다.
6.4.2. Disabling Specific Auto-configuration Classes
원하지 않는 특정 자동 구성 클래스가 있는 경우, 다음 예제와 같이 @SpringBootApplication
의 제외 애트리뷰트를 사용하여 해당 클래스를 비활성화할 수 있다:
자바
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
public class MyApplication {
}
코틀린
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
@SpringBootApplication(exclude = [DataSourceAutoConfiguration::class])
class MyApplication
클래스가 클래스패스에 없으면 어노테이션의 excludeName
애트이뷰트를 사용하는 대신 자격있는 이름(fully qualified name)을 지정할 수 있다. @SpringBootApplication
대신 @EnableAutoConfiguration
을 사용하려는 경우에는 exclude
및 excludeName
도 사용할 수 있다. 마지막으로 spring.autoconfigure.exclude
프로퍼티를 사용하여 제외할 자동 구성 클래스 목록을 제어할 수도 있다.
어노테이션 레벨과 프로퍼티를 사용하여 제외를 정의할 수 있다.
자동 구성(auto-configuration) 클래스가 공개(public) 클래스이더라도, 공개 API 클래스로의 유일한 측면은 자동 구성을 비활성화하기 위해 사용하는 클래스명이다. 중첩된 구성 클래스 또는 빈 메소드와 같은 해당 클래스의 실제 컨텐츠는 내부용으로 사용되며 직접 사용하지 않는 것이 좋다.
6.5. Spring Beans and Dependency Injection
표준 스프링 프레임워크 기술을 자유롭게 사용하여 빈과 주입된 의존성을 정의할 수 있다. 일반적으로 생성자 인젝션(constructor injection)을 사용하여 의존성을 연결하고, @ComponentScan
을 사용하여 빈을 찾는 것이 좋다.
위에서 제안한 대로 코드를 구성하는 경우(최상위 패키지에 애플리케이션 클래스 찾기) 아규먼트 없이 @ComponentScan
을 추가하거나 이를 암시적으로 포함하는 @SpringBootApplication
어노테이션을 사용할 수 있다. 모든 애플리케이션 컴포넌트(@Component
, @Service
, @Repository
, @Controller
등)는 자동으로 스프링 빈으로 등록된다.
다음 예는 필수 RiskAssessor
빈을 얻기 위해 생성자 인젝션을 사용하는 @Service
빈을 보여준다:
자바
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
코틀린
import org.springframework.stereotype.Service
@Service
class MyAccountService(private val riskAssessor: RiskAssessor) : AccountService
빈에 하나 이상의 생성자가 있는 경우 스프링에서 사용하려는 생성자를 @Autowired
로 표시해야 한다:
자바
import java.io.PrintStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyAccountService implements AccountService {
private final RiskAssessor riskAssessor;
private final PrintStream out;
@Autowired
public MyAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
this.out = System.out;
}
public MyAccountService(RiskAssessor riskAssessor, PrintStream out) {
this.riskAssessor = riskAssessor;
this.out = out;
}
// ...
}
코틀린
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.io.PrintStream
@Service
class MyAccountService : AccountService {
private val riskAssessor: RiskAssessor
private val out: PrintStream
@Autowired
constructor(riskAssessor: RiskAssessor) {
this.riskAssessor = riskAssessor
out = System.out
}
constructor(riskAssessor: RiskAssessor, out: PrintStream) {
this.riskAssessor = riskAssessor
this.out = out
}
// ...
}
생성자 인젝션을 사용하면
RiskAssessor
필드가 파이널(final, val)로 표시되어 이후에 변경할 수 없음을 나타내는 것에 주목하자.
6.6. Using the @SpringBootApplication Annotation
대부분의 스프링 부트 개발자는 자동 구성, 컴포넌트 스캔을 사용하고 “애플리케이션 클래스”에 추가 구성을 정의할 수 있는 것을 좋아한다. 싱글 @SpringBootApplication
어노테이션을 사용하여 다음 세 가지 기능을 활성화할 수 있다:
@EnableAutoConfiguration
: 스프링 부트의 자동 구성 메커니즘을 활성화한다.@ComponentScan
: 애플리케이션이 있는 패키지에서@Component
스캔을 활성화한다 (참고: 모범 사례)@SpringBootConfiguration
: 컨텍스트에서 추가 빈을 등록하거나 추가 구성 클래스를 가져올 수 있다. 통합 테스트에서 구성 감지를 돕는 스프링의 표준@Configuration
의 대안이다.
자바
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan과 동일하다
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
코틀린
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
// @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan과 동일하다
@SpringBootApplication
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
Note
@SpringBootApplication
은 @EnableAutoConfiguration
및 @ComponentScan
의 어트리뷰트를 커스텀하기 위한 별칭(aliases)도 제공한다. 이러한 기능은 필수 사항이 아니며 이 싱글 어노테이션을 활성화하여 대체할 수 있다. 예를 들어, 애플리케이션에서 컴포넌트 스캔이나 컨피규레이션 프로퍼티 스캔을 사용하고 싶지 않을 수 있다:
자바
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Import;
@SpringBootConfiguration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import({ SomeConfiguration.class, AnotherConfiguration.class })
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
코틀린
import org.springframework.boot.SpringBootConfiguration
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Import
@SpringBootConfiguration(proxyBeanMethods = false)
@EnableAutoConfiguration
@Import(SomeConfiguration::class, AnotherConfiguration::class)
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}
이 예제에서 MyApplication
은 @Component
어노테이션이 달린 클래스와 @ConfigurationProperties
어노테이션이 달린 클래스가 자동으로 감지되지 않고, 커스텀 빈을 명시적으로 가져오는 점을 제외하면 다른 스프링 부트 애플리케이션과 같다(@Import
참고).
6.7. Running Your Application
애플리케이션을 jar로 패키징하고 임베디드 HTTP 서버를 사용하는 것의 가장 큰 장점 중 하나는 다른 애플리케이션과 마찬가지로 애플리케이션을 즉시 실행할 수 있다는 것이다. 이 샘플은 스프링 부트 애플리케이션 디버깅에 적용된다. 특별한 IDE 플러그인이나 확장이 필요하지 않다.
이 절에서는 jar 기반 패키징만 다룬다. 애플리케이션을 war 파일로 패키징하기로 선택한 경우 서버 및 IDE 설명서를 참고하자.
6.7.1. Running From an IDE
IDE에서 스프링 부트 애플리케이션을 자바 애플리케이션으로 실행할 수 있다. 그러나 먼저 프로젝트를 가져와야 한다. 가져오기 단계는 IDE 및 빌드 시스템에 따라 다르다. 대부분의 IDE는 메이븐 프로젝트를 직접 가져올 수 있다. 예를 들어 이클립스 사용자는 File
메뉴에서 Import
… → Existing Maven Projects
를 선택할 수 있다.
프로젝트를 IDE로 직접 가져올 수 없는 경우, 빌드 플러그인을 사용하여 IDE 메타데이터를 생성할 수 있다. 메이븐에는 이클립스 및 IDEA용 플러그인이 포함되어 있다. 그레이들은 다양한 IDE용 플러그인을 제공한다.
실수로 웹 애플리케이션을 두 번 실행한 경우 “이미 사용 중인 포트” 오류가 표시된다. 스프링 툴(Spring Tools) 사용자는 Run
버튼 대신 Relaunch
버튼을 사용하여 기존 인스턴스가 닫혔는지 확인할 수 있다.
6.7.2. Running as a Packaged Application
스프링 부트 메이븐 또는 그레이들 플러그인을 사용하여 실행 가능한 jar를 생성한 경우, 다음 예제와 같이 java -jar
을 사용하여 애플리케이션을 실행할 수 있다:
$ java -jar target/myapplication-0.0.1-SNAPSHOT.jar
원격 디버깅 지원이 활성화된 패키지 애플리케이션을 실행할 수도 있다. 이렇게 하면 다음 예제와 같이 패키지된 애플리케이션에 디버거를 연결할 수 있다:
$ java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n \
-jar target/myapplication-0.0.1-SNAPSHOT.jar
6.7.3. Using the Maven Plugin
스프링 부트 메이븐 플러그인에는 애플리케이션을 빠르게 컴파일하고 실행 시 사용할 수 있는 실행 목표가 포함되어 있다. 애플리케이션은 IDE에서와 마찬가지로 분해된 형태로 실행된다. 다음 예에서는 스프링 부트 애플리케이션을 실행하는 메이븐 명령을 보여준다:
$ mvn spring-boot:run
다음 예와 같이 MAVEN_OPTS
운영 체제 환경 변수를 사용할 수도 있다.
$ export MAVEN_OPTS=-Xmx1024m
6.7.4. Using the Gradle Plugin
스프링 부트 그레이들 플러그인에는 분해된 형식으로 애플리케이션을 실행하는 데 사용할 수 있는 bootRun
태스크가 포함되어 있다. bootRun
태스크는 org.springframework.boot
및 자바
플러그인을 적용하면 자동 추가되며 다음 예제에 나타난다:
$ gradle bootRun
다음 예와 같이 JAVA_OPTS
운영 체제 환경 변수를 사용할 수도 있다:
$ export JAVA_OPTS=-Xmx1024m
6.7.5. Hot Swapping
스프링 부트 애플리케이션은 일반 자바 애플리케이션이므로 JVM 핫 스와핑(hot-swapping)은 즉시 작동해야 한다. JVM 핫 스와핑은 대체할 수 있는 바이트코드에 따라 다소 제한된다. 보다 완벽한 솔루션을 위해 JRebel을 사용할 수 있다.
spring-boot-devtools
모듈에는 빠른 애플리케이션 재시작 지원이 포함되어 있다. 자세한 내용은 핫 스와핑 “사용 방법”을 참고하자.
6.8. Developer Tools
스프링 부트에는 애플리케이션 개발 경험을 좀 더 즐겁게 만들 수 있는 추가 툴 세트가 포함되어 있다. spring-boot-devtools
모듈은 추가 development-time
기능을 제공하기 위해 모든 프로젝트에 포함될 수 있다. devtools
지원을 사용하려면 메이븐 및 그레이들에 대한 모듈 의존성을 추가하자:
메이븐
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
그레이들
dependencies {
developmentOnly("org.springframework.boot:spring-boot-devtools")
}
Devtools
는 특히 멀티 모듈 프로젝트에서 클래스 로딩 문제를 일으킬 수 있다. 클래스 로딩 문제 진단에서는 문제를 진단하고 해결하는 방법을 설명한다.
완전히 패키지된 애플리케이션을 실행하면 개발자 도구가 자동으로 비활성화된다. 애플리케이션이 java -jar
에서 시작되거나 특수 클래스로더에서 시작되면 “프로덕션 애플리케이션”으로 간주된다. spring.devtools.restart.enabled
시스템 프로퍼티를 사용하여 이 동작을 제어할 수 있다. 애플리케이션을 시작하는 데 사용된 클래스로더에 관계없이 devtools
를 활성화하려면 -Dspring.devtools.restart.enabled=true
시스템 프로퍼티를 설정해보자. devtools
은 보안 위협 될 수 있으므로 프로덕션 환경에서 이 작업을 수행해서는 안 된다. devtools
를 비활성화하려면 의존성을 제외하거나 -Dspring.devtools.restart.enabled=false
시스템 프로퍼티를 설정하자.
메이븐에서 의존성을 옵셔널로 표시하거나 그레이들에서
developmentOnly
구성을 사용하면(위에 표시된 대로)devtools
가 프로젝트를 사용하는 다른 모듈에 전이적으로(transitively) 적용되는 것을 방지할 수 있다.
리패키징된 압축파일에는 기본적으로
devtools
가 포함되어 있지 않다. 특정 원격devtools
기능을 사용하려면 해당 기능을 포함해야 한다. 메이븐 플러그인을 사용하는 경우,excludeDevtools
프로퍼티를false
로 설정하자. 그레이들 플러그인을 사용할 때,developmentOnly
구성을 포함하도록 태스크의 클래스패스를 구성한다.
6.8.1. Diagnosing Classloading Issues
재시작과 리로드 절에 설명된 대로 재시작 기능은 두 개의 클래스로더를 사용하여 구현된다. 대부분의 애플리케이션에서는 이 접근 방식이 잘 작동한다. 그러나 멀티 모듈 프로젝트에서 클래스 로딩 문제가 발생할 수 있다.
클래스 로딩 문제가 실제로 devtools
및 두 클래스로더로 인해 발생했는지 진단하려면 재시작을 비활성화해보자. 문제가 해결되면 전체 프로젝트를 포함하도록 재시작 클래스로더를 커스텀하자.
6.8.2. Property Defaults
스프링 부트에서 지원하는 여러 라이브러리는 성능을 향상시키기 위해 캐시를 사용한다. 예를 들어, 템플릿 엔진은 템플릿 파일을 반복적으로 파싱하는 것을 방지하기 위해 컴파일된 템플릿을 캐시한다. 또한 스프링 MVC는 스태틱(static) 리소스를 제공할 때 응답(response)에 HTTP 캐싱 헤더를 추가할 수 있다.
캐싱은 프로덕션에서 매우 유익하지만 개발 중에는 비생산적일 수 있으므로 방금 애플리케이션에서 변경한 내용을 볼 수 없게 된다. 이러한 이유로 spring-boot-devtools
는 기본적으로 캐싱 옵션을 비활성화한다.
캐시 옵션은 일반적으로 application.properties
파일의 설정으로 구성된다. 예를 들어 Thymeleaf
는 spring.thymeleaf.cache
프로퍼티를 제공한다. 이러한 프로퍼티를 수동으로 설정할 필요 없이 spring-boot-devtools
모듈은 합리적으로 development-time
구성을 자동 적용한다.
다음 표에는 적용되는 모든 프로퍼티가 나열되어 있다:
명칭 | 기본 값 |
---|---|
server.error.include-binding-errors | always |
server.error.include-message | always |
server.error.include-stacktrace | always |
server.servlet.jsp.init-parameters.development | true |
server.servlet.session.persistent | true |
spring.docker.compose.readiness.wait | only-if-started |
spring.freemarker.cache | false |
spring.graphql.graphiql.enabled | true |
spring.groovy.template.cache | false |
spring.h2.console.enabled | true |
spring.mustache.servlet.cache | false |
spring.mvc.log-resolved-exception | true |
spring.reactor.netty.shutdown-quiet-period | 0s |
spring.template.provider.cache | false |
spring.thymeleaf.cache | false |
spring.web.resources.cache.period | 0 |
spring.web.resources.chain.cache | false |
프로퍼티의 기본값을 적용하지 않으려면 application.properties
에서 spring.devtools.add-properties
를 false
로 설정할 수 있다.
스프링 MVC 및 스프링 웹플럭스 애플리케이션을 개발하는 동안 웹 요청에 대한 추가 정보가 필요하기 때문에 개발자 도구에서는 웹(web)
로깅 그룹에 대해 DEBUG
로깅으로 제안한다. 그러면 들어오는 요청, 이를 처리하는 처리기, 응답 결과 및 기타 세부 정보에 대한 정보가 제공된다. 모든 요청 세부 정보(잠재적으로 민감한 정보 포함)를 기록하려면 spring.mvc.log-request-details
또는 spring.codec.log-request-details
구성 프로퍼티를 켤 수 있다.
6.8.3. Automatic Restart
spring-boot-devtools
를 사용하는 애플리케이션은 클래스패스의 파일이 변경될 때마다 자동으로 재시작된다. 이는 코드 변경에 대한 매우 빠른 피드백 루프를 제공하므로 IDE에서 작업할 때 유용한 기능이 될 수 있다. 기본적으로 디렉토리를 가리키는 클래스패스의 모든 항목은 변경 사항을 모니터링한다. 스태틱 자원(static assets) 및 뷰 템플릿과 같은 특정 리소스는 애플리케이션을 재시작할 필요가 없다.
Triggering a restart
DevTools
이 클래스패스 리소스를 모니터링하므로, 재시작을 트리거하는 유일한 방법은 클래스패스를 업데이트하는 것이다. IDE를 사용하든 빌드 플러그인 중 하나를 사용하든 재시작을 트리거하려면 수정된 파일을 재컴파일해야 한다. 클래스패스를 업데이트하는 방법은 사용 중인 도구에 따라 다르다:
- 이클립스에서 수정된 파일을 저장하면 클래스패스가 업데이트되고 재시작된다.
- 인텔리J IDEA에서 프로젝트 빌드(
Build +→+ Build Project
)도 동일한 효과를 갖는다. - 빌드 플러그인을 사용하는 경우 메이븐용
mvn compile
또는 그레이들gradle build
를 실행하면 재시작된다.
빌드 플러그인을 사용하여 메이븐 또는 그레이들을 재시작하는 경우 분기 설정(forking set)을 활성화된 상태로 두어야 한다. 분기 설정을 비활성화하면 devtools
에서 사용하는 격리된 애플리케이션 클래스로더가 생성되지 않고 재시작이 제대로 작동하지 않는다.
LiveReload
와 함께 사용하면 자동 재시작이 매우 잘 작동한다. 자세한 내용은LiveReload
절을 참고하자.JRebel
을 사용하는 경우 다이나믹 클래스 리로드를 위해 자동 재시작이 비활성화된다. 다른devtools
기능(예:LiveReload
및 프로퍼티 오버라이드)은 계속 사용할 수 있다.
DevTools
은 애플리케이션 컨텍스트의 종료 후크를 사용하여 재시작하는 동안 이를 닫는다. 종료 후크(SpringApplication.setRegisterShutdownHook(false)
)를 비활성화한 경우 올바르게 작동하지 않는다.
DevTools
는 애플리케이션컨텍스트(ApplicationContext)
에서 사용하는 리소스로더(ResourceLoader)
를 커스텀해야 한다. 애플리케이션이 이미 제공한 경우, 래핑된다. 애플리케이션컨텍스트에서 getResource
메소드를 오버라이드하는 것은 지원되지 않는다.
AspectJ 위빙(weaving)을 사용할 때는 자동 재시작이 지원되지 않는다.
Restart vs Reload
스프링 부트에서 제공하는 재시작(restart) 기술은 두 개의 클래스로더를 사용하여 작동한다. 변경되지 않는 클래스(예: 서드 파티 jar의 클래스)는 기본 클래스로더에 로드된다. 현재 개발 중인 클래스는 재시작 클래스로더에 로드된다. 애플리케이션이 재시작되면 재시작 클래스 로더가 삭제되고, 새 클래스 로더가 생성된다. 이 접근 방식은 기본 클래스로더가 이미 사용 가능하며 채워져 있으므로 애플리케이션 재시작이 일반적으로 “콜드 스타트(cold starts)”보다 훨씬 빠르다는 것을 의미한다.
애플리케이션을 재시작하는 것이 충분히 빠르지 않거나 클래스 로딩 문제가 발생하는 경우
ZeroTurnaround
에서JRebel
과 같은 기술을 재로드하는 것을 고려할 수 있다. 이는 클래스가 로드될 때 클래스를 재작성하여 재로드하기 쉽게 만드는 방식으로 작동한다.
Logging Changes in Condition Evaluation
기본적으로, 애플리케이션이 재시작될 때마다, 조건 평가 델타(evaluation delta)를 보여주는 보고서가 기록된다. 보고서에는 빈 추가 또는 제거, 구성 속성 설정 등 변경 작업을 수행할 때 애플리케이션의 자동 구성에 대한 변경 사항이 표시된다.
보고서 로깅을 비활성화하려면 다음 프로퍼티를 설정하자:
프로퍼티스(Properties)
spring.devtools.restart.log-condition-evaluation-delta=false
Yaml
spring:
devtools:
restart:
log-condition-evaluation-delta: false
Excluding Resources
특정 리소스는 변경될 때 반드시 재시작을 트리거할 필요가 없다. 예를 들어 Thymeleaf
템플릿은 내부에서 편집할 수 있다. 기본적으로 /META-INF/maven
, /META-INF/resources
, /resources
, /static
, /public
또는 /templates
에서 리소스를 변경하면 재시작(restart)이 트리거되지 않지만 라이브 리로드(live reload)가 트리거된다. 이러한 제외를 커스텀하려면, spring.devtools.restart.exclude
프로퍼티를 사용할 수 있다. 예를 들어 /static
및 /public
만 제외하려면 다음 프로퍼티를 설정하자:
프로퍼티스(Properties)
spring.devtools.restart.exclude=static/**,public/**
Yaml
spring:
devtools:
restart:
exclude: "static/**,public/**"
이러한 기본값을 유지하고 추가 제외를 설정하려면 대신
spring.devtools.restart.additional-exclude
프로퍼티를 사용하자.
Watching Additional Paths
클래스패스에 없는 파일을 변경할 때 애플리케이션을 재시작하거나 리로드할 수 있다. 그렇게 하려면 spring.devtools.restart.additional-paths
프로퍼티를 사용하여 변경 사항을 감시할 추가 경로를 구성해야한다. 앞에서 설명한 spring.devtools.restart.exclude
프로퍼티를 사용하여 추가 경로 아래 변경 사항이 전체 재시작 또는 라이브 리로드를 트리거하는지 여부를 제어할 수 있다.
Disabling Restart
재시작 기능을 사용하지 않으려면 spring.devtools.restart.enabled
프로퍼티를 사용하여 비활성화할 수 있다. 대부분의 경우 application.properties
에서 이 프로퍼티를 설정할 수 있다. 이렇게 하면 클래스로더 재시작이 초기화되지만 파일 변경 사항은 감시되지 않는다.
재시작 지원 기능을 완전히 비활성화해야 하는 경우(예: 특정 라이브러리에서 작동하지 않기 때문에) 다음 예에 표시된 대로 SpringApplication.run(...)
을 호출하기 전에 spring.devtools.restart.enabled
시스템 프로퍼티를 false
로 설정해야 한다:
자바
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApplication.class, args);
}
}
코틀린
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
System.setProperty("spring.devtools.restart.enabled", "false")
SpringApplication.run(MyApplication::class.java, *args)
}
}
Using a Trigger File
변경된 파일을 지속적으로 컴파일하는 IDE로 작업하는 경우 특정 시간에만 재시작을 트리거하는 것을 선호할 수 있다. 이를 위해 실제로 재시작 확인을 트리거할 때 수정해야 하는 특수 파일인 “트리거 파일”을 사용할 수 있다.
파일을 업데이트하면 검사가 시작되지만, 실제로는 Devtools
에서 수행할 작업이 감지된 경우에만 재시작된다.
트리거 파일을 사용하려면, spring.devtools.restart.trigger-file
프로퍼티를 트리거 파일의 이름(경로 제외)으로 설정하자. 트리거 파일은 클래스패스 어딘가에 있어야 한다.
예를 들어 다음과 같은 구조의 프로젝트가 있는 경우:
src
+- main
+- resources
+- .reloadtrigger
그러면 트리거 파일 프로퍼티는 다음과 같다:
프로퍼티스(Properties)
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
이제 재시작은 src/main/resources/.reloadtrigger
가 업데이트될 때만 발생한다.
spring.devtools.restart.trigger-file
을 글로벌 설정하여 모든 프로젝트가 동일한 방식으로 작동하도록 할 수 있다.
일부 IDE에는 트리거 파일을 수동으로 업데이트할 필요가 없도록 해주는 기능이 있다. 이클립스용 스프링 툴(Spring Tools)와 인텔리J IDEA(Ultimate Edition) 모두 이러한 지원을 제공한다. 스프링 툴즈를 사용하면 트리거 파일 이름이 .reloadtrigger인 경우 콘솔에서 “reload” 버튼을 사용할 수 있다. 인텔리J IDEA의 경우 해당 문서의 지침을 따를 수 있다.
Customizing the Restart Classloader
재시작과 리로드 절에서 앞서 설명한 대로 재시작 기능은 두 개의 클래스 로더를 사용하여 구현된다. 이로 인해 문제가 발생하는 경우 어떤 클래스로더에 의해 로드되는 항목을 커스텀해야 할 수도 있다.
기본적으로 IDE에 열려 있는 모든 프로젝트는 “재시작” 클래스로더를 사용하여 로드되고 모든 일반 .jar 파일은 “기본(“base”)” 클래스로더를 사용하여 로드된다. mvn spring-boot:run
또는 gradle bootRun
을 사용하는 경우에도 마찬가지다. @SpringBootApplication
을 포함하는 프로젝트는 “재시작(restart)” 클래스로더로 로드되고 그 외 모든 것은 “기본” 클래스로더로 로드된다.
META-INF/spring-devtools.properties
파일을 생성하여 스프링 부트에 다른 클래스로더를 사용하여 프로젝트의 일부를 로드하도록 지시할 수 있다. spring-devtools.properties
파일에는 restart.exclude
및 restart.include
접두사가 붙은 프로퍼티가 포함될 수 있다. include
엘리먼트는 “재시작” 클래스로더로 끌어 올려야 하는 항목이고, exclude
엘리먼트는 “기본” 클래스 로더로 푸시해야 하는 항목이다. 속성 값은 다음 예에 표시된 것처럼 클래스 경로에 적용되는 정규식 패턴이다.
프로퍼티스(Properties)
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\\.jar
Yaml
restart:
exclude:
companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
include:
projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
모든 프로퍼티 키는 유니크해야 한다. 프로퍼티가 restart.include
또는 restart.exclude
으로 시작하는한 항상 고려해야 한다.
클래스패스의 모든
META-INF/spring-devtools.properties
가 로드된다. 프로젝트 내부 또는 프로젝트가 사용하는 라이브러리에 파일을 패키징할 수 있다.
Known Limitations
표준 오브젝트인풋스트림(ObjectInputStream)
을 사용하여 역직렬화(deserialize)된 객체에서는 재시작 기능이 제대로 작동하지 않는다. 데이터를 역직렬화해야 한다면 Thread.currentThread().getContextClassLoader()
와 함께 스프링의 컨피규러블오브젝트인풋스트림(ConfigurableObjectInputStream)
을 사용해야 할 수도 있다.
불행하게도, 몇몇 서드 파티 라이브러리는 컨텍스트 클래스로더를 고려하지 않고 역직렬화한다. 그러한 문제를 발견하면 라이브러리 개발자에게 수정을 요청해야 한다.
6.8.4. LiveReload
spring-boot-devtools
모듈에는 리소스가 변경될 때 브라우저 새로 고침을 트리거하는 데 사용할 수 있는 내장 라이브리로드(LiveReload)
서버가 포함되어 있다. 라이브리로드(LiveReload)
브라우저 익스텐션은 livereload.com에서 크롬, 파이어폭스 및 사파리용으로 무료로 제공된다.
애플리케이션이 실행될 때 라이브리로드(LiveReload)
서버를 시작하지 않으려면 spring.devtools.livereload.enabled
프로퍼티를 false
로 설정하면 된다.
한 번에 하나의 라이브리로드 서버만 실행할 수 있다. 애플리케이션을 시작하기 전에 다른 라이브리로드 서버가 실행되고 있지 않은지 확인하자. IDE에서 여러 애플리케이션을 시작하는 경우 첫 번째 애플리케이션만 라이브리로드를 지원한다.
파일이 변경될 때, 라이브리로드를 실행하려면 자동 재시작을 활성화해야 한다.
6.8.5. Global Settings
$HOME/.config/spring-boot
디렉토리에 다음 파일을 추가하여 글로벌 devtools 설정
을 구성할 수 있다:
spring-boot-devtools.properties
spring-boot-devtools.yaml
spring-boot-devtools.yml
이러한 파일에 추가된 모든 프로퍼티는 devtools
를 사용하는 컴퓨터의 모든 스프링 부트 애플리케이션에 적용된다. 예를 들어 항상 트리거 파일을 사용하도록 재시작을 구성하려면 spring-boot-devtools
파일에 다음 속성을 추가하자:
프로퍼티스(Properties)
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml
spring:
devtools:
restart:
trigger-file: ".reloadtrigger"
기본적으로 $HOME
은 사용자의 홈 디렉토리다. 이 위치를 커스텀하려면 SPRING_DEVTOOLS_HOME
환경 변수 또는 spring.devtools.home
시스템 프로퍼티를 설정하자.
$HOME/.config/spring-boot
에서 devtools
구성 파일을 찾을 수 없으면 $HOME
디렉토리의 루트에서 .spring-boot-devtools.properties
파일이 있는지 검색하자. 이를 통해 $HOME/.config/spring-boot
위치를 지원하지 않는 이전 버전의 스프링 부트에 있는 애플리케이션과 devtools
글로벌 구성을 공유할 수 있다.
devtools
properties/yaml 파일에서는 프로필(Profiles)이 지원되지 않는다.
.spring-boot-devtools.properties
에서 활성화된 모든 프로필은 프로필별 구성 파일 로드에 영향을 주지 않는다. YAML 및 Properties 파일 모두 프로필별 파일명(spring-boot-devtools-<profile>.properties
포맷) 및 spring.config.activate.on-profile
문서는 지원되지 않는다.
Configuring File System Watcher
파일시스템와처(FileSystemWatcher)
는 특정 시간 간격(certain time interval)으로 클래스 변경 사항을 폴링한 다음 더 이상 변경 사항이 없는지 확인하기 위해 미리 정의된 침묵(quiet) 기간을 기다리는 방식으로 작동한다. 스프링 부트는 IDE에 전적으로 의존하여 파일을 컴파일하고 스프링 부트가 읽을 수 있는 위치로 복사하므로 devtools
가 애플리케이션을 재시작할 때 특정 변경 사항이 반영되지 않는 경우가 있을 수 있다. 이러한 문제가 지속적으로 보인다면 spring.devtools.restart.poll-interval
및 spring.devtools.restart.quiet-period
파라미터를 개발 환경에 맞는 값으로 늘려보자:
프로퍼티스(Properties)
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period=1s
Yaml
spring:
devtools:
restart:
poll-interval: "2s"
quiet-period: "1s"
모니터링되는 클래스패스 디렉토리는 이제 변경 사항에 대해 2초마다 폴링되며, 추가 클래스 변경이 없는지 확인하기 위해 1초의 침묵 기간이 있다.
6.8.6. Remote Applications
스프링 부트 개발자 도구는 로컬 개발에만 국한되지 않는다. 원격으로 애플리케이션을 실행할 때 여러 기능을 사용할 수도 있다. 원격 지원은 보안 위험이 있을 수 있으므로 옵셔널(opt-in)하게 제공됩니다. 신뢰할 수 있는 네트워크에서 실행 중이거나 SSL로 보안이 유지되는 경우에만 활성화해야 합니다. 이러한 옵션 중 어느 것도 사용할 수 없는 경우 DevTools
의 원격 지원을 사용해서는 안 된다. 프로덕션 배포에서는 이 기능을 활성화하면 안 된다.
이를 활성화하려면, 아래 표시된 대로 devtools
가 리패키징된 압축파일에 포함되어 있는지 확인해야 한다. To enable it, you need to make sure that devtools is included in the repackaged archive, as shown in the following listing:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludeDevtools>false</excludeDevtools>
</configuration>
</plugin>
</plugins>
</build>
그런 다음 spring.devtools.remote.secret
프로퍼티를 설정해야 한다. 중요한 비밀번호와 마찬가지로 값은 추측하거나 무차별 공격을 가할 수 없도록 고유하고 강력해야 한다.
원격 devtools
지원은 연결을 허용한 서버 측 엔드포인트와 IDE에서 실행하는 클라이언트 애플리케이션이라는 두 부분으로 제공된다. spring.devtools.remote.secret
프로퍼티가 설정되면 서버 컴포넌트가 자동으로 활성화된다. 클라이언트 컴포넌트를 수동으로 시작해야 한다.
스프링 웹플럭스 애플리케이션에는 원격 devtools
가 지원되지 않는다.
Running the Remote Client Application
원격 클라이언트 애플리케이션은 IDE 내에서 실행되도록 설계됐다. 연결하는 원격 프로젝트와 동일한 클래스패스를 사용하여 org.springframework.boot.devtools.RemoteSpringApplication
을 실행해야 한다. 애플리케이션의 하나의 필수 아규먼트는 연결되는 원격 URL이다.
예를 들어, 이클립스 또는 스프링 툴즈를 사용하고 있고 Cloud Foundry
에 배포한 my-app
이라는 프로젝트가 있는 경우 다음과 같이 수행하자:
Run menu
에서Run Configurations...
을 선택.- 새
자바 애플리케이션
“실행 구성” 생성. my-app
프로젝트를 찾기.org.springframework.boot.devtools.RemoteSpringApplication
을 메인 클래스로 사용.프로그램 아규먼트
(또는 원격 URL이 무엇이든)에https://myapp.cfapps.io
를 추가한다.
실행 중인 원격 클라이언트는 다음과 유사할 수 있다:
. ____ _
/\\ / ___'_ __ _ _(_)_ __ __ _ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | | - \___ _ __ ___| |_ ___\ \ \ \
\\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
=========|_|==============|___/===================================/_/_/_/
:: Spring Boot Remote :: (v3.1.1)
2023-06-22T12:06:32.435Z INFO 20337 --- [ main]
o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication v3.1.1
using Java 17.0.7 with PID 20337
(/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-
devtools/3.1.1/spring-boot-devtools-3.1.1.jar started by myuser in /opt/apps/)
2023-06-22T12:06:32.441Z INFO 20337 --- [ main]
o.s.b.devtools.RemoteSpringApplication : No active profile set, falling back to 1
default profile: "default"
2023-06-22T12:06:32.729Z INFO 20337 --- [ main]
o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-06-22T12:06:32.943Z INFO 20337 --- [ main]
o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.995
seconds (process running for 1.372)
원격 클라이언트는 실제 애플리케이션과 동일한 클래스패스를 사용하기 때문에 애플리케이션 프로퍼티를 직접 읽을 수 있다. 이는 spring.devtools.remote.secret
프로퍼티을 읽고 인증을 위해 서버에 전달하는 방법이다.
트래픽이 암호화되고 비밀번호를 가로챌 수 없도록 항상 https://를 연결 프로토콜로 사용하는 것이 좋다.
원격 애플리케이션에 접근하기 위해 프록시를 사용해야 하는 경우
spring.devtools.remote.proxy.host
및spring.devtools.remote.proxy.port
프로퍼티를 구성하자.
Remote Update
원격 클라이언트는 로컬 재시작과 동일한 방식으로 애플리케이션 클래스패스의 변경 사항을 모니터링한다. 업데이트된 모든 리소스는 원격 애플리케이션에 푸시되고 (필요한 경우) 재시작을 트리거한다. 이는 로컬에 없는 클라우드 서비스를 사용하는 기능을 반복하는 경우 도움이 될 수 있다. 일반적으로 원격 업데이트 및 재시작은 전체 재구축 및 배포 주기보다 훨씬 빠르다.
느린 개발 환경에서는 침묵(quiet) 시간이 충분하지 않아 클래스의 변경 사항이 일괄적으로 분할될 수 있다. 첫 번째 클래스 변경 사항 배치가 업로드된 후 서버가 재시작된다. 서버를 재시작하는 중이므로 다음 배치를 애플리케이션으로 보낼 수 없다.
이는 일반적으로 일부 클래스 업로드 실패 및 그에 따른 재시도에 대한 리모트스프링애플리케이션(RemoteSpringApplication)
로그의 경고로 나타난다. 그러나 이로 인해 애플리케이션 코드 불일치가 발생하고 변경 사항의 첫 번째 배치 처리가 업로드된 후 재시작하지 못할 수도 있다. 이러한 문제가 지속적으로 보인다면 spring.devtools.restart.poll-interval
및 spring.devtools.restart.quiet-period
파라미터를 개발 환경에 맞는 값으로 늘려보자. 이러한 프로퍼티를 구성하려면 파일 시스템 와처(File System Watcher) 절을 참조하자.
파일은 원격 클라이언트가 실행 중일 때만 모니터링된다. 원격 클라이언트를 시작하기 전 파일을 변경하면 원격 서버로 푸시되지 않는다.
6.9. Packaging Your Application for Production
실행 가능한 jar는 프로덕션 배포에 사용될 수 있다. 독립형이므로 클라우드 기반 배포에도 이상적으로 적합하다.
상태(health), 감사(auditing), 메트릭(metric) REST 또는 JMX 엔드포인트와 같은 추가적인 “프로덕션 준비” 기능을 위해 spring-boot-actuator
추가를 고려해보자. 자세한 내용은 프로덕션 준비 기능(Production-ready)을 참고하자.
6.10. What to Read Next
이제 스프링 부트를 사용하는 방법과 따라야 할 몇 가지 모범 사례를 이해해야 한다. 이제 특정 스프링 부트 기능에 대해 자세히 알아볼 수도 있고, 스킵 후 스프링 부트의 “프로덕션 준비” 측면에 대해 읽어볼 수도 있다.