스프링 부트 개발자 도구
코드를 수정할 때 애플리케이션을 자동으로 재시작하는 방법
브라우저 새로고침을 자동으로 실행하는 라이브 리로드 사용법
프로젝트 리액터 디버깅 도구
애플리케이션 시작 시간 단축
- 예전에는 코드 수정 시 애플리케이션에 반영하기 위해 애플리케이션을 계속 재시작을 해야 했기에 불편했음
- 스프링 부트가 나오기 전부터 스프링 프레임워크는 무거운 애플리케이션 서버 대신 서블릿 컨테이너를 선택해서 재시작 문제 해결을 시도함
- 위의 시도에도 충분하지 않음
- 스프링 부트가 나오면서 내장형 서블릿 컨테이너라는 혁신을 이뤄냄
- 기존의 WAR 파일을 만들어서 톰켓과 같은 서블릿 컨테이너에 애플리케이션을 배포하는 방식이 아닌 애플리케이션에 서블릿 컨테이너를 포함하는 방식
- 서블릿 컨테이너를 애플리케이션에 포함하며 생긴 변화
- 애플리케이션 시작 속도를 높임
- 배포 개념의 변화
- 더 이상 운영 담당자가 설치하고 운영하는 서블릿 컨테이너에 종속되지 않음
- 서블릿 컨테이너를 어떻게 사용할지 주체적으로 선택해서 지정 가능
- JVM만 설치되어 있으면 어떤 장비에도 JAR 파일을 배포해서 서블릿 컨테이너가 포함된 애플리케이션 실행
- 스프링 부트 개발팀은 여기에서 그치지 않고 애플리케이션을 더 빨리 실행할 수 있는 개선 방법 연구함
개발자 도구(DevTools)
- 스프링 부트 개발팀은 내장형 서블릿 컨테이너의 혁신에 이어 DevTools라는 새로운 개발자 도구를 만듦
- 개발자 도구 포함 기능
- 애플리케이션 재시작(restart)과 리로드(reload) 자동화
- 환경설정 정보 기본값 제공
- 자동 설정(autoconfiguration) 변경사항 로깅
- 정적 자원 제외
- 라이브 리로드(LiveReload) 지원
- 의존 관계 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
자동 재시작과 리로딩
- 스프링 부트 개발팀에서 애플리케이션 개발 속도를 높이기 위해 사용자 코드 변화를 감지하고 애플리케이션을 재시작하는 기능 추가함
- 재시작과 리로딩
- 개발자가 작성한 코드를 하나의 클래스 로더가 로딩하고 서드파티 라이브러리는 별도의 클래스 로더로 로딩
- 애플리케이션이 재시작되면 개발자가 작성했던 코드를 로딩했던 클래스 로더도 종료되고 새로운 클래스 로더가 사용됨
- 서드파티 라이브러리를 로딩했던 클래스 로더는 그대로 남음
- 개발자 코드만 새로 리로드 하여 모든 것을 새로 시작하는 콜드(Cold) 시작 방식보다 훨씬 빨리 애플리케이션을 재시작할 수 있음
- 리로드 개선 효과를 최대로 끌어내려면 JRebel 같은 자바 에이전트 솔루션 필요
정적 자원 제외
- 스프링 부트는 기본적으로 다음과 같은 자원에는 변경이 발생해도 재시작을 하지 않음
- /META-INF/maven
- /META-INF/resources
- /resources
- /static
- /public
- /templates
- 정적 자원 변경 내용은 대부분의 웹 기술에서 재부팅 없이도 서버에 반영할 수 있음으로 애플리케이션 재시작을 유발하지 않음
- 변경사항이 재시작을 유발하지 않게 하는 경로를 변경하는 방법
spring.devtools.restart.exclude=static/**,public/**
- 개발자 도구에 의한 재시작 자체를 비활성화
spring.devtools.restart.enabled=false
개발 모드에서 캐시 비활성화
- 스프링 부트와 통합되는 많은 컴포넌트는 다양한 캐시 수단을 가지고 있음
- ex. 어떤 템플릿 엔진의 경우 컴파일된 템플릿을 캐시함
- 스프링 부트에서 타임리프 캐시 설정 비활성화
spring.thymeleaf.cache=false
부가적 웹 활동 로깅
- 특정 패키지 내의 모든 파일에 사용된 모든 로깅 파일을 변경하거나, 클래스 수준 디버깅 설정을 뒤져보지 않아도 간단하게 web 로깅 그룹의 로그를 출력해서 웹 수준에서 어떤 일이 수행되는지 확인 가능
- 개발자 도구를 사용해 Web 로깅 그룹의 로그 수준을 DEBUG로 지정
logging.level.web=DEBUG
자동 설정에서의 로깅 변경
- 스프링 부트 2부터 자동 설정의 기본값과 다르게 설정된 내용만 확인할 수 있도록 변경사항을 관리함
- ex. 어떤 빈을 추가해서 자동설정 기본값과 다르게 구성됐다면 그 달라진 내용만 보여줌
라이브 리로드 지원
- 개발자 도구에 라이브 리로드 서버가 내장돼 있음
- 서버가 재시작됐을 때 웹 페이지를 새로 로딩하는 단순한 작업을 수행함
- ex. 서버가 재시작됐을 때 브라우저의 새로고침 버튼을 자동으로 눌러줌
- 라이브 리로드를 사용하라면 백엔드에서 서버를 실행해야 하고 브라우저에도 LiveReload 플러그인을 설치해야 함
리액터 개발자 도구
리액터 플로우 디버깅
- 리액터 처리 과정은 일반적으로 여러 스레드에 걸쳐 수행될 수 있으므로 스택 트레이스를 통해 쉽게 확인할 수 없음
- 리액터는 나중에 구독에 의해 실행되는 작업 흐름을 조립하는 비동기, 논블로킹 연산을 사용
- 자바 스택 트레이스는 동일한 스레드 내에서만 이어지며, 스레드 경계를 넘어서지 못함
- 리액터는 스택 트레이스를 통해 가능한 한 가장 먼 곳까지 따라가지만 다른 스레드의 내용까지 쫓아가지는 못함
- 이 한계를 극복을 위해
Hooks.onPeratorDebug()메소드 호출 필요Hooks.onPeratorDebug()를 호출하면 리액터가 처리 흐름 조립 시점에서의 호출부 세부 정보를 수집하고 구독해서 실행되는 시점에 세부정보를 넘겨줌- 리액터가 스레드 별 스택 세부 정보를 스레드 경계를 넘어서 전달하는 과정에서 굉장히 많은 비용이 발생
- 운영환경 또는 실제 벤치마크에서는
Hooks.onPeratorDebug()를 절대로 호출하면 안 됨 - 호출해야만 한다면 적절한 조건을 사용해서 해당 조건을 만족할 때만 실행되게 해야 함
- 리액터는 확장성 있는 애플리케이션을 만들 수 있는 수단을 제공함과 동시에 개발자의 디버깅을 돕는 도구도 함께 제공
리액터 플로우 로깅
- 리액터에서는 실행 후에 디버깅하는 것 외에 실행될 때 로그를 남길 수도 있음
- 리액터 코드에
log.debug()를 사용해보면 전통적인 명령행 코드에서와 달리 원하는 대로 출력하는 것이 쉽지 않음- 리액티브 스트림이 비동기라는 특성 때문이 아닌 리액터가 적용한 함수형 프로그래밍 기법에서 비롯된 문제
- 로깅 때문에 간결한 코드를 쓸 수 없음
- 람다식에 로깅 코드를 추가하며 장황한 코드로 변경됨
- 리액터는 이 문제에 대해 다른 방법 제시
- 리액터 연산자 사이에. log() 추가
log()에 인자로 넘겨진 문자열 토큰과 리액티브 스트림 시그널 모두 출력 가능
블록 하운드를 사용한 블로킹 코드 검출
- 블록하운드
- 리액터 개발팀에 소속된 세르게이 에고로프가 만듦
- 개발자가 직접 작성한 코드뿐만 아니라 서드파티 라이브러리에 사용된 블로킹 메소드 호출을 모두 찾아내서 알려주는 자바 에이전트
- 블로킹 코드가 소스 어디에도 없고 관련 설정도 적절하다는 것을 보장
- 의존관계 추가
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<version>1.0.3.RELEASE</version>
</dependency>
- 블록 하운드 자체로는 아무 일도 하지 않지만 애플리케이션에 적절하게 설정되면 자바 에이전트 API를 이용해서 블로킹 메소드를 검출하고, 해당 쓰레드가 블로킹 메소드 호출을 허용하는지 검사할 수 있음
- 블록하운드 등록
public static void main(String... args) {
BlockHound.install(); // 스프링 부트 애플리케이션 시작할 때 블록하운드가 바이트코드를 조작할 수 있음
SpringApplication.run(HackingSpringBootApplication.class, args);
}
- 블록하운드 옵션
- 특정 블로킹 호출을 문제로 인식하지 않도록 허용 리스트에 등록
- 특정 부분을 블로킹으로 인지되도록 금지 리스트에 등록
- 샘플 코드
// BlockHound.install(); // 스프링 부트 애플리케이션 시작할 때 블록하운드가 바이트코드를 조작할 수 있음
BlockHound.builder()
// 허용 리스트 추가
.allowBlockingCallsInside(
TemplateEngine.class.getCanonicalName(), "process")
// 커스텀 설정이 적용된 블록하운드가 애플리케이션에 심어짐
.install();
참고
- "스프링 부트 실전 활용 마스터", 그렉 턴키스트 저(원서: "Hacking with Spring Boot 2.3 - Reactive Edition")
- 소스 코드
'dev > Spring' 카테고리의 다른 글
| [정리] 스프링 부트 실전 활용 마스터(6) (0) | 2022.06.30 |
|---|---|
| [정리] 스프링 부트 실전 활용 마스터(5) (0) | 2022.06.23 |
| [정리] 스프링 부트 실전 활용 마스터(4) (0) | 2022.06.16 |
| [정리] 스프링 부트 실전 활용 마스터(2) (0) | 2022.05.19 |
| [정리] 스프링 부트 실전 활용 마스터(1) (0) | 2022.05.12 |