이번에 스프링 부트를 사용하게 되면서 좀 더 다양한 dependency를 추가해보고 경험해볼 기회가 있었는데
그중에 굉장히 유용하게 사용하게 되었던 기능이 있어 포스팅해봅니다.
스프링 부트를 사용하게 되면서 처음으로 접해본 Spring initializr였는데 프로젝트를 생성할때 스프링의 스타터팩과는
다르게 직접 원하는것만 설정해서 의존성 설정을 할 수 있는것이 편리하게 느껴졌었습니다. 이 편리함으로 시작한
스프링 부트에서 더욱더 빠르게 프로젝트를 완성시킬 수 있도록 도와주는 기능이 있었는데 바로
Spring Boot Dev Tools 였습니다.
Spring Boot의 개발문서에 따르면 이렇게 설명 되어있습니다.
Spring Boot에는 애플리케이션 개발을 좀 더 즐겁게 만들어 줄 수 있는 추가 도구 세트가 포함되어 있습니다.
spring-boot-devtools 모듈은 추가 개발 시간 특징을 제공하기 위해 어떤 프로젝트에도 포함될 수 있습니다.
devtools를 포함하려면 빌드에 모듈 종속성을 추가하기 만하면됩니다.
그래서 오늘 공부해본 Spring Boot Dev Tools의 설명을 한마디로 요약하자면
수동으로 재시작 하지 않아도 클래스패스에 변경이 생기면 자동으로 변경사항이 적용되어 보여지게 만들어주는 도구
입니다.
개발문서를 읽어보니 여러 특징과 팁들이 있었습니다.
docs.spring.io/spring-boot/docs/1.5.16.RELEASE/reference/html/using-boot-devtools.html
DevTools의 특징
- Property Defaults [ 속성 기본값 ]
- Automatic Restart [ 자동 재시작 ]
- Live Reload [ 실시간 리로드 ]
- Global Settings [ 전역 설정 ]
- Remote Applications [ 원격 어플리케이션 ]
Property Defaults
스프링 부트가 지원하는 여러 라이브러리는 성능 향상을 위해서 캐시를 사용합니다. 템플릿 엔진을 예로들어 볼수있죠
반복되는 구문을 분석하지 않도록 컴파일된 템플릿을 캐싱합니다. 캐싱은 완성품에서는 매우 유용하지만 개발 중에는
생산성이 떨어질 수 있으므로캐싱은 프로덕션에 매우 유용하지만 개발 중에는 비효율적일 수 있으므로 어플리케이션에
서 방금 변경한 내용을 확인할 수 없습니다. spring-boot-devtools는 기본적으로 이러한 캐싱 옵션을 비활성화합니다.
이러한 이유로, Devtools는 기본적으로 이러한 캐시 옵션을 비활성화합니다.
spring-boot GitHub 의 DevToolsPropertyDefaultsPostProcessor.java 에서 보았을때
속성 기본값들은 다음과 같습니다.
devToolsProperties.put("spring.thymeleaf.cache", "false"); |
devToolsProperties.put("spring.freemarker.cache", "false"); |
devToolsProperties.put("spring.groovy.template.cache", "false"); |
devToolsProperties.put("spring.mustache.cache", "false"); |
devToolsProperties.put("server.session.persistent", "true"); |
devToolsProperties.put("spring.h2.console.enabled", "true"); |
devToolsProperties.put("spring.resources.cache-period", "0"); |
devToolsProperties.put("spring.resources.chain.cache", "false"); |
devToolsProperties.put("spring.template.provider.cache", "false"); |
devToolsProperties.put("spring.mvc.log-resolved-exception", "true"); |
devToolsProperties.put("server.jsp-servlet.init-parameters.development", "true"); |
devToolsProperties.put("spring.reactor.stacktrace-mode.enabled", "true"); |
Automatic restart
아마 이부분이 제일 편리한 부분이 아닐까 하는데요. 클래스 패스에서 파일의 변화가 감지될 때마다 어플리케이션이 자동적으로 재시작 될 수 있도록 합니다. 정적 리소스 및 뷰 템플릿과 같은 특정 리소스는 응용 프로그램을 다시 시작 할 필요가 없습니다
※ 재시작 방법은 사용중인 IDE에 따라 조금 차이가 나는데 가장 많이 쓰이는 eclipse(STS), IntelliJ의 방법을 보면
Eclipse는 클래스패스에 수정된 파일이 저장되면 재시작하고, IntelliJ는 빌드하면 재시작됩니다.
Restart VS Reload
Spring Boot에서 제공하는 재시작 기술은 두 개의 클래스 로더를 사용하여 작동합니다.
변경되지 않는 클래스 [ ex) 타사의 jar클래스 같은 것들 ]는 기본 클래스 로더에 로드 됩니다.
현재 개발중인 클래스는 restart클래스 로더에 로드됩니다. 어플리케이션이 재시작 되면 restart클래스 로더가 버려지고 새 클래스 로더가 작성됩니다. 이러한 접근 방식은 기본클래스 로더가 이미 사용 가능하고 채워져 있으므로 일반적으로 응용 프로그램 restart가 coldstart(캐시된 데이터가 없는 상태로 처음부터 시작한 경우) 보다 훨씬 빠르다는 것을 의미합니다.
restart 가 어플리케이션에 충분히 빠르지 않거나 클래스 로딩 문제가 발생하는 경우 JRebel과 같은 기술을 reload하는 것을 생각해볼 수 있다고 합니다. ( 흠.. ? )
Restart VS Reload
Spring Boot에서 제공하는 재시작 기술은 두 개의 클래스 로더를 사용하여 작동합니다.
변경되지 않는 클래스 [ ex) 타사의 jar클래스 같은 것들 ]는 기본 클래스 로더에 로드 됩니다.
현재 개발중인 클래스는 restart클래스 로더에 로드됩니다. 어플리케이션이 재시작 되면 restart클래스 로더가 버려지고 새 클래스 로더가 작성됩니다. 이러한 접근 방식은 기본클래스 로더가 이미 사용 가능하고 채워져 있으므로 일반적으로 응용 프로그램 restart가 coldstart(캐시된 데이터가 없는 상태로 처음부터 시작한 경우) 보다 훨씬 빠르다는 것을 의미합니다.
restart 가 어플리케이션에 충분히 빠르지 않거나 클래스 로딩 문제가 발생하는 경우 JRebel과 같은 기술을 reload하는 것을 생각해볼 수 있다고 합니다. ( 흠.. ? )
- Excluding resources ( 리소스 제외 )
Dev-tools를 사용하여 재시작하고 싶지 않을 경우 exclude 설정을 통하여 리로드 항목에서 제외할 수 있습니다.
Ex ) /static 경로와 /public 로를 제외 설정하고싶다면
-> spring.devtools.restart.exclude = static/**, public/** 로 설정가능
- Watching additional paths ( 추가 경로 주시)
클래스패스에 없는 파일을 변경할 때 spring.devtools.restart.additional-path 속성 이용해서 어플리케이션을 다시 시작하거나 다시 로드할 수 있습니다.
- Disabling restart ( 재시작 기능 비활성화 )
spring.devtools.restart.enabled 속성을 사용하여 활성화 가능합니다. 이경우 클래스 로더가 초기화 되지만 파일 변경사항은 감시하지 않습니다. 재시작 지원을 완전히 비활성화해야하는 경우, 특정 라이브러리에서 작동하지 않기 때문에 SpringApplication.run (…)을 호출하기 전에 System 속성을 설정해야 합니다.
재시작 기능 비활성화의 예시
public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(MyApp.class, args);
}
- Using a trigger file ( 트리거 파일 사용 )
변경된 파일을 지속적으로 컴파일해야하는 IDE작업을 하는 경우 특정한 때에만 재시작을 하는것이 좋습니다.
변경을 할때마다 재시작되게되면 번거롭기 때문이죠. 그래서 이렇게 특정한 때에만 재시작을 하도록 하려면 재시작 검사를 할때 수정해야 하는 특수 파일인 trigger file을 사용할 수 있습니다. 파일을 변경하면 검사하고 Devtools가
무언가를 수행해야 한다고 감지한 경우에만 다시 시작되게 됩니다. trigger file은 수동또는 IDE 플러그인을 통해
업데이트 할 수 있습니다.
※ spring.devtools.restart.trigger-file 속성을 사용하면 특정 파일을 수정할 때만 재시작하게 끔 설정 가능합니다.
- Customizing the restart classloader ( 재시작 클래스로더 커스터마이징 )
위의 Restart VS Reload 에서 설명한 대로 restart 기능은 두 개의 클래스 로더를 사용하여 구현되며 대부분의 응용
프로그램에서 접근 방식은 잘 작동하지만 때로는 클래스 로딩 문제가 발생할 수 있습니다.
기본적으로 IDE에서 열려있는 모든 프로젝트는 restart 클래스 로더를 사용하여 로드되고 일반 jar파일은 "기본"클래스 로더를 사용하여 로드됩니다. 다중 모듈 프로젝트에서 작업하고 각 모듈을 IDE로 가져 오지 않는 경우 항목을 사용자 정의해야 할 수 있습니다. 이를 위해 META-INF / spring-devtools.properties파일을 생성 할 수 있습니다.
이 파일은 restart.exclude 와 restart.include 속성을 포함할 수 있습니다.
include 속성은 restart 로더에 pull up 한다는 의미이며, exclude 속성은 기본 로더로 push down 해야할 사항이라는 의미입니다. 정규표현식으로 해당 파일의 속성값을 나타낼 수도 있습니다.
정규표현식으로 나타낸 properties의 속성 예시 )
restart.exclude.companycommonlibs=/mycorp-common-[\\w-]+\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w-]+\.jar
- Known limitations ( 알려진 제약사항 )
restart 기능은 표준 ObjectInputStream을 사용하여 역 직렬화 된 개체에서는 제대로 작동하지 않습니다.
만약 역직렬화된 데이터가 필요하다면 스프링의 ConfigurableObjectInputStream와 Tread.currenThread().getContextClassLoader()를 같이 사용할 필요가 있을 것입니다.
LiveReload
spring-boot-devtools모듈은 리소스가 변경 될때 브라우저를 리플레시 하는데 사용할 수 있는 내장형 LiveReloadServer를 포함하고 있습니다. LiveReload 브라우저 확장프로그램은 크롬, 파이어 폭스, 사파리 등에서 livereload.com을 통하여 자유롭게 이용할 수 있습니다.
애플리케이션이 실행될 때 LiveReload 서버를 시작하지 않으려면 spring.devtools.livereload.enabled 속성을
false로 설정하면 됩니다.
※ 한 번에 하나의 LiveReload 서버만 실행할 수 있고 응용 프로그램을 시작하기 전에 다른 LiveReload 서버가 실행되고 있는지 확인이 필요합니다. IDE에서 여러 애플리케이션을 시작하는 경우 첫 번째 애플리케이션만 LiveReload를 지원한다고 합니다.
Global Setting
위에도 언급했던 spring-boot-devtools.properties를 ${HOME} 경로 폴더에 추가함으로써 devtools의 전역설정을 정의 할 수있습니다. 이렇게 하면 이 파일에 추가된 모든특성은 해당 컴퓨터의 모든 SpringBoot 어플리케이션에 적용이 됩니다.
Remote applications
※ < 이부분은 추후 조금 더 알아보고 업데이트 하도록하겠습니다. >
Maven과 Gradle의 Dependency 간단한 설정 방법 ( 위 : Maven / 아래 : Gradle )
//pom.xml 의존설정 [ Maven ]
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
//build.gradle 의존설정 [ Gradle ]
dependencies{
compile('org.springframework.boot:spring-boot-devtools')
}
의존성 설정후 해당 pom.xml 이나 build.gradle파일을 업데이트(갱신) 해주고
[ application.properties ]
- spring.devtools.livereload.enabled=true
- view단이 바뀌었을 때 자동으로 리로드 설정입니다.
- spring.devtools.restart.enabled=false
- 컨트롤러, 모델단이 바뀌었을 때 프로젝트 재시작 설정입니다. (정확히는 classpath에 있는 모든 파일)
- 이부분은 true 설정시 너무 프로젝트 재시작 빈도가 너무 잦아서 false로 설정해 놓았습니다.
이클립스의 경우 project -> build automatically 설정
IntelliJ의 경우 registr 에서 compiler.automake.allow.when.app.running 체크,
settings > build > compiler에서 Build project automatically 체크 하시면 됩니다.
※ maven으로 bootrun 구동해야한다고합니다.
이클립스의 경우 project -> build automatically 설정
IntelliJ의 경우 registr 에서 compiler.automake.allow.when.app.running 체크,
settings > build > compiler에서 Build project automatically 체크 하시면 됩니다.
※ maven으로 bootrun 구동해야한다고합니다.
혹시 잘못된 정보가 있어 알려주신다면 수정하겠습니다.
피드백해주시면 감사히 듣겠습니다.
댓글