스프링부트 애플리케이션 개발가이드

…​ 쓴다면... 목차는 이렇게 잡을 듯 싶다. 쓸지는 모르겠지만...


Table of Contents

1. 개발환경 설정

1.1. JDK 설치

1.2. STS 설치

1.3. 그레이들Gradle 설치


2. 스프링부트 살펴보기

스프링부트 살펴보기

2.1. Hello, SpringBoot

별도의 설정없이 spring-boot-starter-web 만을 이용한 웹 애플리케이션 만들기

2.2. 스프링부트 특징소개

2.3. 스프링부트 시동절차 설명

2.4. 스프링부트 구조 설명

2.5. 실행가능한 내장형 jar


3. 스프링부트 환경 소개

3.1. 시스템요구사항

3.2. 빌드 시스템

3.2.1. 빌드툴 선택: 메이븐Maven or 그레이들 Gradle

3.2.2. Starter POM

3.2.3. 의존성관리

3.3. 패키지 형태 선택: jar or war

배포할 목적에 따라 선택

3.3.1. jar

3.3.2. war

3.4. 프로젝트 구조

3.4.1. 기본패키지 default 사용

3.4.2. 메인 클래스 위치

3.5. 애플리케이션 환경구성

3.5.1. 구성 클래스 설정

3.5.2. XML 임포트

3.6. 자동구성

debug=true 을 이용해서 조건에 부합하여 활성화된 자동구성과 그렇지 않은 자동구성 확인

3.6.1. 자동구성 대체하기

3.6.2. 자동구성 비활성화하기

3.6.3. 설정파일을 이용한 활성화 선택

3.7. 스프링 빈과 의존성 주입

3.8. 애플리케이션 실행

3.8.1. IDE

3.8.2. packaged application

3.8.3. Gradle 플러그인 사용

3.9. 개발자도구 dev-tools

3.10. 애플리케이션 압축포장

실행가능한 jar


4. 스프링부트 기능

4.1. 스프링 애플리케이션SpringApplication

4.2. 구성 확장하기

4.2.1. Properties 대신 YAML 사용

4.2.2. 타입-세이프 구성 프로퍼티즈

4.3. 프로필 Profil 사용

4.4. 로깅logging

4.5. 웹 애플리케이션 개발

4.5.1. 스프링 웹 MVC 프레임워크

4.5.2. 내장 서블릿 컨테이너 지원

4.6. 데이터베이스 동작

4.6.1. H2

4.6.2. JPA

4.7. 테스트

4.7.1. TDD로 한다?

4.8. 자동구성 만들기

넣을까 말까.

4.8.1. 자동구성된 빈에 대한 이해

4.8.2. 음..

거창하다.


5. 스프링부트 액츄에이터: 출시준비 기능

5.1. 출시준비 기능 활성화

5.2. 엔드포인트

5.3. 모니터링과 관리

5.3.1. HTTP

5.3.2. JMX

5.3.3. Remote shell

5.4. 측정

5.5. 프로세스 모니터링


6. 빌드

6.1. 의존성 버전 변경

6.2. 실행가능한 jar 만들기


7. 스프링부트 배포

7.1. 전통적인 배포가능한 war 배포

7.2. 스프링부트 설치

7.2.1. 유닉스/리눅스 서비스 등록

7.3. 클라우드 배포

7.3.1. Heroku

7.3.2. AWS

7.4. 도커Docker 배포


8. 부록

8.1. 개발을 위해 기능확인 방법

  • 스프링부트 레퍼런스 문서 참고

  • 관련 자동구성 클래스 확인

  • debug=true 를 이용한 활성화된 자동설정과 비활성화된 자동설정 확인

8.2. 실행가능한 jar 구조


기본구성되어 있는 스프링부트가 구동되면 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 를 사용하지 않으면 문제 없음


+ Recent posts