기본구성되어 있는 스프링부트가 구동되면 JmxAutoConfiguration 구성이 구동된다. 이 JMX 구성 덕분에 로컬에서는 jconsole을 이용해서 애플리케이션의 상태를 모니터링할 수 있다.

오우!!

스프링부트 애플리케이션을 구동하고

구동될 때 구성을 살펴볼 수 있도록 application.propertiesdebug=true 속성을 부여하면 나오는 항목 중에 보면

JmxAutoConfiguration matched
     - @ConditionalOnClass classes found: org.springframework.jmx.export.MBeanExporter (OnClassCondition)
     - matched (OnPropertyCondition)
 
  JmxAutoConfiguration#mbeanExporter matched
     - @ConditionalOnMissingBean (types: org.springframework.jmx.export.MBeanExporter; SearchStrategy: current) found no beans (OnBeanCondition)
 
  JmxAutoConfiguration#mbeanServer matched
     - @ConditionalOnMissingBean (types: javax.management.MBeanServer; SearchStrategy: all) found no beans (OnBeanCondition)
 
  JmxAutoConfiguration#objectNamingStrategy matched
     - @ConditionalOnMissingBean (types: org.springframework.jmx.export.naming.ObjectNamingStrategy; SearchStrategy: current) found no beans (OnBeanCondition)

들을 볼 수 있다.

스프링부트 애플리케이션 구동이 완료되고

로컬에 떠있는 프로세스들 중에서 살펴보려는 스프링부트 애플리케이션을 선택하고



연결이 완료되면 다음의 항목들을 볼 수 있다.








@_@) 지금까지는 성능이나 모니터링에 대해서 관심이 높지 않았는데 이에 대해서도 관심을 가져야겠다 싶어졌다.

흠... 아마, 운영에 대한 경험이 없기 때문이 무관심했던 것이 아닐까?

위에서 보여지는 그래프에 대한 정보는, 스프링부트에 액츄에이터actuator 기능을 추가하면 REST API로 로 /beans, /metrics 등의 정보로 제공되기도 한다.

프론트엔드쪽도 잘하면... 이를 이용해서 간단한 대시보드를 만들어볼텐데... @_@);;


STS의 스프링부트 대시보드: 1부 - 로컬 부트앱

스프링 커뮤니티 유저 여러분.

이 글은 STS에 추가된 스프링부트 대시보드에 관한 소식을 전하기 위한 세 개의 글 중에서 처음으로 작성된 글이다. IDE에서 스프링부트 대시보드를 어떻게 사용하는지를 살펴보고, 그것이 제공하는 다양한 기능들, 스프링부트 기반의 애플리케이션을 개발할 때,을 어떻게 사용할지를 배운다. 스프링부트 대시보드는 얼마전 출시된 STS 3.7.1에서 소개되었으며, 이 연재 블로그를 따라하기 위해서는 해당버전 이상을 필요하다. 만약 설치하지 않았다면,http://spring.io/tools/ 으로 가셔서 내려받아 설치하기 바란다.

1. 소개

현재 스프링부트는 엔터프라이즈 환경을 위한 애플리케이션 구현을 간단하게 해주는 범용적인 기술이 되었다. 마이크로서비스 기반 애플리케이션을 만들어내는데 적합하며, 스프링 애플리케이션 설정을 쉽고 작게 생각하도록 극적인 변화를 이끌었다. 진정으로 클라우드 친화적인 애플리케이션으로 문을 열고 스프링 클라우드와 더불어 아마 많은 마이크로서비스로 구성될 것이다.

이 극적인 이동은 아키텍처에 대한 우리의 생각들이 IDE에도 반영되길 원하게 되었다. 전통적인 자바 통합개발도구IDE 대부분이 클라우드 친화적인 혹은, 클라우드 이전 그리고 분산 프로그래밍 시대 이전에 만들어졌다. 이는 이클립스 IDE가 그러하고 그것을 기반으로 하는 Spring Tool Suite(STS) 또한 그러하다. 이 IDE들은 클라우드 친화적인 시대에 들어섰다. 이는 스프링부트 대시보드의 시작점이 되었다. 스프링부트 대시보드는 수많은 스프링부트 기반의 마이크로서비스 애플리케이션을 관리하고 IDE 내 프로젝트들을 동작시키는 개발자들의 삶을 윤택하게 만들기 위해 만들어졌다.

2. 스프링부트 대시보드

작게 점진적으로 시작하자면, 스프링부트 대시보드는 STS/Eclipse의 추가적인 뷰로 구성됬다. 기본 툴바의 스프링부트 버튼을 누르면 열어볼 수 있다. 간단한 뷰가 열리고 작업공간의 (스프링부로 구성된)프로젝트들이 동기화되며 나타난다.

01-dashboard.png

스프링부트 대시보드의 주요목적은 매일, 매시간, 매번 빈번하게 살펴보는 것들에 대해서 빠르게 접근할 수 있도록 하는데 있다. 대시보드에 있는 부트앱을 선택하고 툴바에서"run" 혹은 "debug"를 눌러 빠르게 시작할 있다. 부트앱을 실행할 수 있는 이보다 빠른 방법이 있을까? 이미 실행중인 앱의 코드가 변경되어 재시작하고 싶다면 그렇게 하면 된다. 코드가 변경되었을 때, 대시보드의 "run" 버튼을 눌러, 앱을 정지 또는 재시작시킬 수 있다. 다시말하지만, 한번 클릭으로 간단하게 할 수 있게 되었다.

02-start-single.png

부트 대시보드의 이런 동작들은 단일 혹은 다중 프로젝트에서도 동일하게 수행된다. 만약 동시에 다수의 부트 앱, 협업을 위해 필요한 서비스의 묶음,을 시작하거나 정지하길 원한다면, 대시보드에서 그것들을 모두 선택하고 "run"을 누르면 된다. 그것만 하면 된다.

03-start-multiple.png

프로젝트들을 스프링부트 1.3 적용하면, 부트 대시보드는 보다 환상적인 것들을 보여줄 것이다. 부트 앱이 구동되고 나면, 부트 대시보드에는 앱이 시동 단계(VM은 실행중이지만, 앱은 아직 초기화중)와 다른 시각적 표현이 나타나며 이는 실행 중인지 완료된 것인지를 명확하게 알려준다. 진행중 아이콘은 앱이 시동주이라는 것을 표시하고, 녹색 "업up" 아이콘은 앱의 초기화 및 실행이 완료되었다는 것을 알려준다. 로그 출력으로 "server started" 메시지가 출력되길 기다리며 살펴보는 등의 행동을 할 필요가 없다. 부트 대시보드 아이콘들을 살펴보자.

04-starting.png

앱이 실행되면, 대시보드에는 사용자의 편의를 위해 동작중인 앱이 사용하는 포트가 표시된다. 앱이 사용하고 있는 포트가 몇번인지 찾기 위해서 로그 출력물을 탐색할 필요가 없다. 대시보드에 그 정보가 자동적으로 표시된다. 그리고 실행중인 부트앱의 콘솔로 빠르게 이동이 가능하며, 그 동작은 매우 신속하고 간단하다.

더이상 실행중인 앱에 바로 브라우저로 접근하기 위해 실행중인 앱의 포트를 알고 있을 필요가 없어졌다. 부트 대시보드에서 프로젝트를 더블클릭하기만 해도 새로운 브라우저가 앱에 기본설정된 URL로 접근할 것이다.

05-browser.png

기본적으로 Eclipse/STS는 내부 인터넷 브라우저 뷰를 사용한다. 만약 외부 인터넷을 사용하려 한다면 설정에서 지정해야 한다.

기본으로 접근해야할 기본 URL이 지정되어있지 않다면, 그것을 사용자설정할 수 있다. 대시보드에서 프로젝트를 선택하고 속성뷰를 열어 URL 경로를 Path에 입력한다. 앱을 더블클릭하면 사용자설정한 URL로 열리는 것을 확인할 수 있을 것이다.

06-path.png

애플리케이션에 정의된 URL 확장이 명확하지 않다면, 속성뷰 창에서 "Request Mapping"을 선택할 수 있다. 실행중인 앱의 모든 리퀘스트 매핑 목록 - 여러분이 정의한 것들은 상단에, 라이브러리들에 의해 생성된 것들은 하단에 위치한다. 리퀘스트 매핑 목록에서 URL 부분을 클릭하면 해당 URL을 브라우저에서 열고, 코드 부분을 클릭하면 해당 프로젝트의 코드 편집기를 통해 해당 코드를 연다.

07-request-mappings.png


역자주

"org.springframework.boot:spring-boot-starter-actuator"를 추가해줘야 /mappingsAPI를 이용해서 앱의 Request Mapping 목록을 조회할 수 있다.

작업공간에서 보다 많은 마이크로서비스를 가지고 있다면, 그것들 모두가 동시에 동작하지 않을 가능성이 있다. 그렇다면 묶음설정을 좋아할 것이다. 예를 들자면 Eclipse/STS에서, 작업 묶음을 만드는 것과 같다. 부트 대시보드는 프로젝트에 임의의 갯수로 태그를 선언하여 태그하는 것을 허용한다(다시 속성 뷰를 보자). 태그는 필터 박스(부트 대시보드 상단에 위치)를 이용해서 부트 대시보드에 보이는 부트 앱을 줄이는데 사용할 수 있다.

08-filter.png


역자주
속성창에서 Tags 항목에 입력이 가능하다. ㅡ_-)

화면으로는 명확하게 안보여.

3. 견해

연재 두번째 글에서는 부트 대시보드의 클라우드 파운더리Cloud Foundry 통합을 소개하면서, 부트 대시보드로부터 CF로 마이크로서비스를 어떻게 배포하는지, 로컬 부트 앱을 사용하여 CF에 배포하는 조합 사용법을 소개하겠다.


이제 스프링부트 1.3.1 과 1.2.8 사용가능

스프링부트 1.2.8과 1.3.0이 출시되었으며 현재 repo.spring.ioMaven Central을 통해서 내려받을 수 있다.

아직 스프링부트 1.3을 사용해보지 않았다면 바로 지금이 사용해볼 때다. 1.3.1에서는 126개의 결함수정과 향상이 있었으며, 절반이상은 풀 리퀘스트(pull request, 스프링부트는 깃헙에서 오픈소스로 개발되고 있다). 이런 징글징글한 컨트리뷰터들에게 고마움을 다시 한번 표한다.

스프링부트 1.2.8 는 결함수정 및 향상 섹션의 보수된 출시다.

또한 우리는 보안 취약점을 수정했으며, 모든 스프링 유저들에게 즉시 업그레이드를 하기를 강력하게 권장한다.

[스프링부트] 1.3.0: spring-boot-devtools 사용시 ModelMapper에서

스프링부트 1.3.0 에서 가장 주목할만한 기능중 하나로 개발도구dev-tools 의 추가를 들 수가 있다. 반응형 프로그래밍reactive programming 의 개념을 도입하여 개발중에 소스코드의 변경이 발생할 경우 변경사항이 구동중인 앱에 반영되는 기능이다.

1.3.0 버전 전에는 classloader를 이용해서 그런 기능을 대신하고 있었다.

스프링부트의 devtools 는 똑같은 두개의 앱을 띄워서 변경사항이 발생하면 컴파일을 하고 그 변경사항을 적용한 앱으로 교체해주는 기작이라고 보면 된다. 그런데 스프링부트의 이런 기능이 ModelMapper의 동작방식과 충돌을 일으킨다. 스프링에서 빈으로 등록한 ModelMapper가 뒤에 있는 앱에 빌드가 되어 재적재reload를 수행하려고 할 때 결함이 발생하며 앱이 죽어버리는 문제가 생긴다.

dev-tools를 사용하지 않던가 모델매퍼modelMapper를 사용하지 않던가 둘 중에 하나를 선택해야 한다.

ㅡ_-);; DTO 객체 정보를 엔티티에 매핑하기 귀찮아서 사용했었는데 여기서 발목을 잡힐 줄이야...

다음 프로젝트에서는 모델매퍼를 사용하지 않을 계획이기는 하지만...

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.modelmapper.ModelMapper io.honeymon.message.MessageServiceImpl.modelMapper; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'modelMapper' defined in class path resource [io/honeymon/configuration/WebConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) Failed to configure mappings

1 error at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:295) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101) [spring-boot-1.3.0.RELEASE.jar:1.3.0.RELEASE] at io.honeymon.Application.main(Application.java:34) [bin/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25] at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) [spring-boot-devtools-1.3.0.RELEASE.jar:1.3.0.RELEASE] Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.modelmapper.ModelMapper io.honeymon.message.MessageServiceImpl.modelMapper; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'modelMapper' defined in class path resource [io/honeymon/configuration/WebConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) Failed to configure mappings

1 error at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] ... 22 common frames omitted Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'modelMapper' defined in class path resource [io/honeymon/configuration/WebConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) Failed to configure mappings

1 error at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1192) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] ... 24 common frames omitted Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) Failed to configure mappings

1 error at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] ... 36 common frames omitted Caused by: org.modelmapper.ConfigurationException: ModelMapper configuration errors:

1) Failed to configure mappings

1 error at org.modelmapper.internal.Errors.throwConfigurationExceptionIfErrorsExist(Errors.java:241) ~[modelmapper-0.7.5.jar:na] at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:207) ~[modelmapper-0.7.5.jar:na] at org.modelmapper.internal.TypeMapImpl.addMappings(TypeMapImpl.java:72) ~[modelmapper-0.7.5.jar:na] at org.modelmapper.internal.TypeMapStore.getOrCreate(TypeMapStore.java:101) ~[modelmapper-0.7.5.jar:na] at org.modelmapper.ModelMapper.addMappings(ModelMapper.java:93) ~[modelmapper-0.7.5.jar:na] at io.honeymon.configuration.WebConfiguration.modelMapper(WebConfiguration.java:228) ~[bin/:na] at io.honeymon.configuration.WebConfiguration$$EnhancerBySpringCGLIB$$27012ff3.CGLIB$modelMapper$11() ~[bin/:na] at io.honeymon.configuration.WebConfiguration$$EnhancerBySpringCGLIB$$27012ff3$$FastClassBySpringCGLIB$$a53168eb.invoke() ~[bin/:na] at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.2.3.RELEASE.jar:4.2.3.RELEASE] at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318) ~[spring-context-4.2.3.RELEASE.jar:4.2.3.RELEASE] at io.honeymon.configuration.WebConfiguration$$EnhancerBySpringCGLIB$$27012ff3.modelMapper() ~[bin/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25] at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE] ... 37 common frames omitted

Caused by: java.lang.ClassCastException: io.honeymon.agent.Agent$$EnhancerByModelMapper$$3d7a6a28 cannot be cast to io.honeymon.agent.Agent at io.honeymon.common.mapper.AgentDtoToAgentPropertyMap.configure(AgentDtoToAgentPropertyMap.java:25) ~[bin/:na] at org.modelmapper.PropertyMap.configure(PropertyMap.java:383) ~[modelmapper-0.7.5.jar:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25] at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25] at org.modelmapper.internal.ExplicitMappingBuilder.build(ExplicitMappingBuilder.java:195) ~[modelmapper-0.7.5.jar:na] ... 51 common frames omitted

참고사항

  • ClassCastException in ModelMapper: EnhancerByModelMapper cannot be cast

    SpringBoot의 dev-tools도 앱을 reload 하기 위해 빈을 등록하는 과정에서 ModelMapper 빈을 등록하는 과정에서 앞서 등록된 propertyMap과 충돌을 일으킨다. ModelMapper의 propertyMap 관리부분이 캐시로 등록되어 있어서 중복선언되면서 충돌하는 부분이랄까...? dev-tools 를 사용하지 않으면 문제 없음


1. FlywayDB

애플리케이션의 변경에 따라 DB 스키마의 변경이력을 관리하기 위한 목적으로 사용한다.

2. SpringBoot에서 제공하는 FlywayDB 관련설정

# FLYWAY (FlywayProperties)
flyway.baseline-description= #
flyway.baseline-version=1 # version to start migration
flyway.baseline-on-migrate= #
flyway.check-location=false # Check that migration scripts location exists.
flyway.clean-on-validation-error= #
flyway.enabled=true # Enable flyway.
flyway.encoding= #
flyway.ignore-failed-future-migration= #
flyway.init-sqls= # SQL statements to execute to initialize a connection immediately after obtaining it.
flyway.locations=classpath:db/migration # locations of migrations scripts
flyway.out-of-order= #
flyway.password= # JDBC password if you want Flyway to create its own DataSource
flyway.placeholder-prefix= #
flyway.placeholder-replacement= #
flyway.placeholder-suffix= #
flyway.placeholders.*= #
flyway.schemas= # schemas to update
flyway.sql-migration-prefix=V #
flyway.sql-migration-separator= #
flyway.sql-migration-suffix=.sql #
flyway.table= #
flyway.url= # JDBC url of the database to migrate. If not set, the primary configured data source is used.
flyway.user= # Login user of the database to migrate.
flyway.validate-on-migrate= #

baseline-version은 별도로 설정하지 않아도 된다.

버전을 별도로 지정하지 않는다면 설정항목을 변경하지 않아도 된다.

3. SpringBootApplication 설정

3.1. build.gradle: flywayDB 의존성 추가

/**
 * http://flywaydb.org/
 * FlywayDB: DB Schema version management tool
 */
compile "org.flywaydb:flyway-core"

3.2. application.yml: flywayDB properties 설정

spring:
  profiles: production
  profiles.include: logging-info, logging-daily
  datasource:
    initialize: false
    sql-script-encoding: UTF-8
    driver-class-name: org.h2.Driver
    url: jdbc:h2:file:~/.h2database/test-db;CACHE_SIZE=10240;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=15000;MVCC=true;
    username: tester //sa 계정을 사용하지 않으려고...
    password: tester
  jpa:
    hibernate:
      ddl-auto: validate
logging:
  file: logs/tester.log
flyway:
  enabled: true
  encoding: UTF-8
  user: sa
  password:

3.3. V1__xxxx.sql 추가

CREATE SCHEMA IF NOT EXISTS "PUBLIC";
CREATE USER IF NOT EXISTS tester PASSWORD 'tester';
ALTER USER tester ADMIN TRUE;
GRANT ALL TO tester;
 
-- DDL 스크립트
....

파일명을 기준으로 하여 버전관리

version comment 사이는 __ 2개의 언더바로 구분지어야 한다.


+ Recent posts