아직까지 Springboot 1.x 를 사용하는 곳이 많지 않을 테지만,

혹시라도 1.x 에서 2.x 버전으로 마이그레이션을 준비하는 분들이 있다면 도움이 될까 해서 올려봅니다.

 

생각보다 1.x에서 2.x로의 변경되는 부분들이 상당히 많습니다.

 

본 글은 실제 운영중인 프로젝트를 마이그레이션하면서 중요하다고 생각되는 부분들을 정리한 내용이니,

아래의 절차대로 진행하신다면 큰 문제없이 2.x로 마이그레이션을 하실 수 있을꺼라 생각합니다.

 

혹시라도 내용중에 미흡한 부분이나, 빠진 부분이 있다면 덧글로 남겨주세요.

 

마이그레이션 진행중에 도움을 받았던 문서들은 아래에 따로 링크를 남겨 두었으니

참고하시면서 진행하시면 더 도움이 되실꺼라 생각합니다.


마이그레이션 시 고려사항 - 꼭 정확한 것은 아닙니다.

  • 1.x → 2.x로의 메이저 업데이트이기 때문에 단순히 스프링부트 버전만 올려서 적용하면, 수많은 컴파일에러와 런타임시의 각종 트러블을 직면하게 됩니다.

  • 따라서 주요변경사항 및 기존 의존성 라이브러리의 버전 확인 후 2.x에서 지원하는 버전으로 교체를 병행하는게 좀 더 안전합니다.

  • 바로 2.3.4버전으로 한번에 업데이트 하지않고 1.5 → 2.0 → 2.3 1.5 → 2.1→ 2.3의 순서로 순차적 업데이트 진행하는 방법을 선택했습니다. 

 

마이그레이션 순서 ( 공식 가이드 방식대로 진행 )

1. gradle을 사용하는 경우, 5.0버전으로 업데이트

  • gradle > wrapper > gradle-wrapper.properites 파일  변경

distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip

 

2. 마이그레이션 지원 라이브러리 의존성 추가 → 마이그레이션 완료이후 삭제

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-properties-migrator</artifactId>
    <scope>runtime</scope>
</dependency>

 

3. Springboot 버전 변경

  •   2.1.6.RELEASE 

 

4. 라이브러리 교체와 주요 변경사항 수정 

  • 컴파일 오류 수정

  • 아래의 스프링부트 2.x버전 주요 변경사항 표 참조

 

5. application-properties 수정

  1. springboot migrator가 제안한 warning 표시에 따라 수정

 

6. bean overiding 설정변경 (필요시)

  1. bean overriding이 디폴트로 'false'로 설정됨. bean overriding사용하려면 아래의 설정추가 

spring.main.allow-bean-definition-overriding=true

 

 7. db설정에 timezone 명시

  1. jdbc url에  '?characterEncoding=UTF-8&serverTimezone=Asia/Seoul' 추가

8. 2.1 → 2.3.x 2차 업데이트 

  • 4,5번 작업 반복

  • 2.3버전의 필수 변경사항

    • Validation 모듈 독립화로 별도 의존성 라이브러 추가필요 - springboot-web-starter 킷에서 제거됨.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

 

 

9. 테스트 수행 

상용서비스의 경우, 대부분 주요 기능에 대한 Test Case가 만들어져 있을겁니다.
컴파일 오류를 모두 수정했다하더라도 주요기능, 사실은 모든 기능에 대한 테스트는 필수입니다.


특히, 데이타 변환, 매핑로직에서의 검증은 반드시 해야하는 절차이니 만약 Test Case가 없다면

별도로 생성해서 수행하는 과정을 꼭 진행하시기 바랍니다. 

 

10. 마이그레이션 지원 라이브러리 의존성 제거

  • 테스트까지 모두 정상적으로 완료되었다면 2번 항목에서 추가한 마이그레이션용 라이브러리를 제거합니다.


 

스프링부트 공식사이트에서 마이그레이션 가이드 및  마이그레이션시

프로퍼티 변경사항을 알려주는 별도의 마이그레이터 라이브러리를 제공합니다.

 

꼭 아래의 공식 가이드 문서를 참고하셔셔 마이그레이션을 진행하는 것을 추천드립니다.

 

  • 스프링부트 마이그레이션 공식가이드

  • 마이그레이션 모듈 (프로퍼티 변경사항에 한함)

    •  spring-boot-properties-migrator

    • 해당 모듈을 마이그레이션 하려는 어플리케이션의 의존성 라이브러리에 추가하면, 런타입시 변경사항 분석 및 레포팅(로그출력)기능 제공

    • 변경된 프로퍼티가 존재하면 WARN 레벨의 로그로 출력되며, 삭제된 프로퍼티를 사용하는 경우 ERROR 레벨의 로그를 출력

 

 

스프링부트 2.x 버전 주요 변경사항

2.x에서 변경된 주요내용에 대해서 표로 정리해 보았습니다. 

변경점

상세내용

임베디드 컨테이너 커스텀 인터페이스 및 클래스 변경

EmbeddedServletContainerCustomizer → WebServerFactoryCustomizer
ConfigurableEmbeddedServletContainer → ConfigurableServletWebServerFactory
TomcatEmbeddedServletContainerFactory → TomcatServletWebServerFactory

기본 데이타베이스 커넥셕풀 라이브러리 변경

Tomcat-JDBC → HikariCP
- 별도의 DataSource 구현시 org.springframework.boot.jdbc.DataSourceBuilder를 통해서 구현해야 함.
- 관련링크: https://jojoldu.tistory.com/296

JPA 2.0 에서 id Auto_increment 관련 수정

이슈 - SpringBoot 버전별 id 생성전략의 차이

  - 1.5 - Hibernate의 id생성전략을 따라가지 않음

  - 2.x - Hibernate의 id생성전략을 따라감


Hibernate 5.x 부터 MySQL의 자동키 생성전략은 IDENTITY가 아닌 TABLE을 기본 시퀀스 전략으로 선택
  - 따라서 Springboot 2.x버전에서 MySQL의 키 전략을 @GeneratedValue(strategy = GenerationType.AUTO) 로 사용하게 되면 TABLE기반으로 시퀀스 생성을 시도 → DB등록시 아래의 에러가 발생

select next_val as id_val from hibernate_sequence for update

could not read a hi value 

해결방안

  1. Hibernate의 생성전략을 따라가지 않도록 프로터티 명시 → 해당 방법으로 변경

spring.jpa.hibernate.use-new-id-generator-mappings=false

  2. 키 생성전략을 IDENTITY로 변경
@GeneratedValue(strategy = GenerationType.IDENTITY)
 

참고

- https://jojoldu.tistory.com/295

- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#id-generator

JPARepository API 변경

PageRequest Deprecated

- 기존: new PageRequest(firstResult, maxResults, new Sort(...))
- 변경: PageRequest.of(firstResult, maxResults, Sort.by(...))

엑추에이터 API 변경

자체 매트릭 API → Micrometer 사용

스프링 소셜에 대한 Auto Configuration 제외

의존성라이브러리 제거됨

Redis 드라이버 변경

Jedis → Lettuce (리액티브 스택지원에 따른 변경사항인듯)

엘라스틱서치 라이브러리 버전변경

5.4

org.springframework.boot.bind 패키지 사용불가

- 바인딩 관련 어노테이션 사용불가
- spring-boot-admin 1.5.7 사용불가

mysql 드라이버 관련

com.mysql.jdbc.Driver → com.mysql.cj.jdbc.Driver

- log4jdbc를 사용할 경우, 현재 사용하고 있는 라이브러리가 내부적으로 com.mysql.jdbc.Driver 를 사용하기 때문에, 어플리케이션 구동시 경고메세지 출력됨

수정방법

- log4jdbc.log4j2.properties 파일에 아래의 속성값 추가

My SQL 5.1.X 이후 버전부터 KST 타임존을 인식하지 못하는 이슈 해결
- 해결방법

  - jdbc url에 파라메터 속성값 추가 - serverTimezone=Asia/Seoul  → 해당방법으로 진행  
  - MySQL 설정파일(my.ini)에 속성값 추가
     - KST로 지정

체크포인트

- 상용의 경우, db커넥션을 맺을때 소스내의 프로파일을 읽지 않고, 각각의 별도서버에 있는 datasource.properties파일의
url을 사용함.
- 형상관리없이 수백대의 서버에 정적으로 관리는 프로퍼티 파일이라 모든 서버의 프로퍼티 파일내 url에 'serverTimezone=Asia/Seoul'을 추가하기에는 너무 큰 비용발생. ( 레거시에서 빨리 개선되어야 하는 이슈중 하나입니다...)

- 임시방편으로 어플리케이션내 ConfigDataSource 클래스 파일에서 얻어온 url에 속성을 추가하는 방식으로 적용

validation 라이브러리 추가

PageablePageBased를 사용하는 모든 class

PageablePageBased 생성자 메서드의 인자중 Sort값이 Null일 경우(정렬이 필요없는 경우), 
아래의 에러발생 - Sort인자값이 필수가 됨.

 변경 방법
  - 기존 생성자 활용, Sort인자값에 null 대신 Sort.unsorted()로 전달 → 이 방법이 기존소스의 변경을 최소화 할 수 있음.
      - new PageablePageBased(pageNum, listCount, null) → new PageablePageBased(pageNum,
listCount, Sort.unsorted())

  - PageRequest.of() 으로 대체
      - new PageablePageBased(pageNum, listCount, null)) → PageRequest of(int page+1, int size)

jpa관련 springframework data의 api 스펙변경

org.springframework.data.repository.support.Repositories.getRepositoryFor(String entityName) 의
반환값이 Object → Optional<Object>로 변경

변경전

변경후

validator 클래스 변경

기존
org.hibernate.validator.constraints.NotBlank
org.hibernate.validator.constraints.NotEmpty

변경:
javax.validation.constraints.NotBlank
javax.validation.constraints.NotEmpty

WebMvcConfigurerAdapter deprecated

기존 : extends WebMvcConfigurerAdapter
변경 : implements WebMvcConfigurer

SpringBootServletInitializer 패키지 이름의 변경

기존 : import org.springframework.boot.web.support.SpringBootServletInitializer
변경 : import org.springframework.boot.web.servlet.support.SpringBootServletInitializer

oauth 관련 라이브러리 변경

기존

변경

SpringBoot 2.x 에서 oauth2 호환성 유지방법 - https://hue9010.github.io/spring/OAuth2/

Spring Security 관련

Security 버전변경으로 PasswordEncoder의 보안기능이 강화됨. 패스워드(or SecretKey)에 {noop}를 추가해야 함.
대상파일: RepositoryOauthClientDetail

기존
baseClientDetails.setClientSecret(oauthClientDetails.getClientSecret());
변경
baseClientDetails.setClientSecret("{noop}"+oauthClientDetails.getClientSecret());


참고자료

 - AuthenticationManager Autowired 오류관련

https://newvid.tistory.com/entry/spring-boot-20-%EC%97%90%EC%84%9C-security-%EC%82%AC%EC%9A%A9%EC%8B%9C-AuthenticationManager-Autowired-%EC%95%88%EB%90%A0%EB%95%8C

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide#authenticationmanager-bean


- PasswordEndcoder 관련 이슈

https://blusky10.tistory.com/411

https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released

 

 

누락된 부분이나 잘못 알고 있는 부분이 충분히 있을 수 있으니,

그런 부분이 있다면 덧글로 남겨주시면 반영하도록 하겠습니다. 


실제로 작업하면서 참고했던 문서들입니다. 

스프링부트 버전별 의존성 라이브러비 버전 Appendix

 

기타 참고자료

 

 

이 글을 읽는, 마이그레이션을 준비하거나 진행중이신 보든 개발자분들, 성공적으로 마이그레이션 하시기를 기원합니다. 

 

PS. 이 글을 쓰고 있는 중에 springboot 2.4가 나왔... ㅠㅠ , R2DBC모듈이 스프링부트 기본모듈에 포함되었다고 합니다. ㅠㅠ

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기