1. 이슈 사항
- 2023년 11월 24일부로 Spring Boot 2.7.x 버전대의 지원이 종료를 끝으로 Spring Boot 2의 모든 지원 종료
- OSS 지원 종료에 따른 여러 불이익 발생으로 한샘 내에서도 기존 사용중인 Spring Boot 2의 버전업이 필요
2. Spring Boot 2 지원 종료에 따른 영향
- start.spring.io 이용한 2.x 프로젝트 생성 불가
- 패치/보안 업데이트 부족으로 인한 리스크 발생
- 신규 라이브러리 추가시 호환성 문제 발생 가능성
3. Spring Boot 3 변경 사항
- 최소 JDK 버전 요구사항 - JDK 17 이상
- 최소 Gradle 버전 요구 사항 - Gradle 7.5 이상
- 최소 Maven 버전 요구 사항 - Maven 3.6.3 이상
- 최소 Hibernate 버전 요구 사항 - Hibernate 6.1
- 로깅 방식 변경
- Java EE → Jakarta EE (Java의 상표권 → Oracle)
- javax.persistence.* ➔ jakarta.persistence.*
- javax.validation.* ➔ jakarta.validation.*
- javax.servlet.* ➔ jakarta.servlet.*
- javax.annotation.* ➔ jakarta.annotation.*
- javax.transaction.* ➔ jakarta.transaction.*
등등
- Spring Boot 2 버전 Deprecated API의 완전 삭제
- URL 매핑 방식 변경
- /api/v1/member 와 /api/v1/member/ 는 이제 다른 URL로 취급
- Log Date Format 변경
- Logback 및 Log4j2 로그 메세지의 날짜와 시간 기본 포맷이 ISO-8601 표준을 준수하도록 변경
- 새로운 기본 포맷은 yyyy-MM-dd’T’HH:mm:ss.SSSXXX으로, T를 이용해 날짜와 시간을 분리하며 타임존을 뒤에 붙임
- LOG_DATEFORMAT_PATTERN 환경 변수 또는 logging.pattern.dateformat 옵션을 통해 기존 값인 yyyy-MM-dd HH:mm:ss.SSS로 표현 가능
- Log Format이 Default로 설정되어 있다면, 의도하지 않게 로그 포맷이 변경되어 영향을 미치지는 않을지 확인해야함
- Spring MVC에서 더 이상 type 레벨의 @RequestMapping 탐색을 지원하지 않음
- interface에 @RequestMapping을 붙여도 더 이상 탐색 되지 않음
따라서 Class 에서만 사용 혹은 interface에서 사용하고 싶다면 @Controller 어노테이션 추가 필요
Spring-cloud-openfeign에서 interface 레벨 @RequestMapping 지원 종료
- interface에 @RequestMapping을 붙여도 더 이상 탐색 되지 않음
4. Spring Boot 3 마이그레이션
Spring Boot 3.0 Migration Guide
4.1 사전 준비
- 마이그레이션 시작시 공식문서 참고
- Spring Boot 버전이 최신 버전과 비교해 많이 낮은 상태라면, 업데이트할 때 바로 3버전으로 업데이트보다는 마이너 버전부터 한 단계식 순차적으로 진행하는 것을 권장
4.2 Spring Boot 3 마이그레이션 순서 (참고용)
- 프로젝트에서 JDK 17 이하 버전을 사용중이라면, JDK 17로 버전업 진행
- (Spring Boot 2 최신 버전 전제) Spring Boot 버전을 3으로 업데이트
- Java EE를 Jakarta EE로 변경
- 코드 레벨에서의 가장 큰 변화는 Javax 패키지의 jakarta 패키지로의 변경
- 수기로 하는 것보다는 IDE의 기능을 이용해 일괄 변경하거나, 공식 문서의 몇가지 방법 혹인 IntellJ에서 지원하는 Java EE에서 Jakarta EE로 리팩토링하는 기능을 이용
- 작업이 끝난 후 IDE의 전체 검색 기능으로 javax.* 검색을 통해 다시 한번 확인
- 주의 사항- 기존 Java EE 에서 제공하는 것이 아닌 JDK에서 제공하는 패키지들 javax.sql , javax.crypto 패키지는 변화 없음
- application.yml 혹은 application.properties 수정
- ex) 아래 Redis의 Config 는 spring.redis.port가 spring.data.redis.port로 수정됨
- # As-Is spring: redis: port: 6379 # To-Be spring: data: redis: port: 6379
- config 설정 마이그레이션 방법
- 해당 옵션값이 언급된 공식 문서를 참고하여 수동 변경
- spring-boot-properties-migrator 사용하여 변경
런타임 시점에 property 들을 migration 하며, 마이그레이션 이후에는 삭제 필요
위 모듈을 추가한 후 Compile 실행시 properties 항목을 스캔하고 현재 Spring Boot 버전 기준으로 변경점이 존재할 경우 WARN 레벨 메시지 출력
- 완전 삭제된 Deprecated API 수정
- Spring Boot 2 버전에서 Deprecated 되었던 API가 Spring Boot 3 에서는 완전 삭제됨
- IDE 자동 완성 기능 혹은 Javadoc 확인하여 코드를 최신 버전으로 수정
- 이외 Spring Boot 3 기능 변경 사항 체크
(URL 매핑 방식, Logging Date Format 변경, @RequestMapping 관련) 확인 - 각 팀 파트내에서 프로젝트에 적용된 외부 라이브러리, 혹은 타사 프로젝트를 확인후
해당 라이브러리, 프로젝트에서에서 제공하는 Jakarta EE 9 및 Spring Framework 6 호환 릴리즈 확인후 적용
- Spring Data JPA
- Spring Boot 3.1 이상부터 Hibernate 6.2 버전 사용
- Hibernate에서 TimeZone 정보를 다루는 방식이 달라짐
Hibernate 6.2부터 시간대 관련 정보는 hibernate.timezone.default_storate 옵션으로 설정
이 옵션은 내부적으로 TimeZoneStorageType Enum 값과 매핑되며, Hibernate가 시간 관련 정보를 실제 DB 테이블에 저장하고 읽을때 어떤식으로 값을 ‘보간’ 하는지 조정함
만약 별다른 옵션을 주지 않으면 hibernate.timezone.default_storage=DEFAULT 로 설정되고 아래와 같이 동작함
- DB 에서 timestamp with timezone 타입의 컬럼을 지원하는 경우 → DB에 절대시간과 시간값을 저장함
- DB 에서 timestamp with timezone 타입의 컬럼을 지원하지 않는 경우 → UTC로 값을 치환하여 저장함 - Hibernate에서는 기존 저장 데이터 및 애플리케이션의 하위 호환성을 지원하기 위해 NORMALIZE 옵션을 제공하며 해당 옵션은 Hibernate 6.2 이전 버전과 동일한 방식으로 동작하도록 설정하는 옵션
해당 옵션을 꼭 설정해 놓아야 기존 데이터와의 정합성을 보장하며 기존과 동일한 방식으로 DB 테이블에 데이터 저장이 가능함 - spring: jpa: properties: hibernate: timezone.default_storage: NORMALIZE
- Query DSL
- Jakarta EE 변경에 따른 Query DSL gradle 설정 변경 필요
- dependencies { implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api" }
- Spring Security
- Spring Boot 3 부터 Spring Security 6 버전을 사용 (많은 변화)
- Security Configratuon 설정방식이 상속에서 빈을 등록하는 방식으로 변경
Spring Security 5 코드
Spring Security 6 코드- @EnableWebSecurity 어노테이션 내부 @Configuration 어노테이션이 제거 되어 별도로 선언 필요
- WebSecurityConfigurerAdapter 클래스가 삭제되었으며, 관련설정 클래스를 Spring Bean으로 설정 해야함
- 2번의 영향으로 HttpSecurity 설정 시 HttpSecurity 설정시 SecurityFilterChain Bean을 직접 선언하여 등록
- 2번의 영향으로 WebSecurity 설정 시 WebSecurityCustomizer Bean을 직접 선언하여 등록
- @Configuration // 1 @EnableWebSecurity public class SecurityConfigSecurity6 { // 2 // HttpSecurity 설정 // 3 @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authorize -> authorize .requestMatchers("/api/admin/**").hasRole("ADMIN") .requestMatchers("/login").permitAll() .anyRequest().authenticated()); http.httpBasic(Customizer.withDefaults()); return http.build(); } // WebSecurity 설정 @Bean public WebSecurityCustomizer webSecurityCustomizer() { // 4 return web -> web.ignoring().requestMatchers("/ignore1", "/ignore2"); } }
- @EnableWebSecurity public class SecurityConfigSecurity5 extends WebSecurityConfigurerAdapter { // HttpSecurity 설정 @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/admin/**").hasRole("ADMIN") .anyRequest().authenticated(); http.httpBasic(Customizer.withDefaults()); } // WebSecurity 설정 @Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/ignore1", "/ignore2"); } }
- Spring Data JPA
- Spring Batch
- @EnableBatchProcessing 더이상 필요 X
- 배치 잡 관련 코드 변경
- https://techblog.lycorp.co.jp/ko/how-to-migrate-to-spring-boot-3
- 유저 동선에 따른 시나리오 작성 후 테스트 및 카나리 배포 방식 사용
5. Spring Boot 3 참고 사항(번외)
- HTTP API 에러 처리를 위한 RFC 7807 지원
- RFC 7807은 API 에러 응답에 대한 표준 규격
- Spring 6.0의 spring-web 모듈에 ProblemDetail Class를 통해 해당 표준을 따는 에러 응답 포맷을 제공
- Spring Native(feat. GraalVM)
- Spring Project이 더 다양한 기능과 높은 안정성을 가지며 업데이트 될수록 서버 실행 시간과 속도, 메모리 사용량은 늘어나고 있음 → 대안으로 Graal VM 개발
- GraalVM을 이용해서 생성되는 Spring 이미지는 JVM을 이용해 생성되는 파일과 다른 Native Image가 생성된다.
이때 생성되는 이미지는 JIT 컴파일러가 아닌 AoT 컴파일러를 이용해 생성된다.
기존 JIT Compiler : Java code → Compile → Class Code(Byte Code) → JVM → Machine Code
AoT Compiler : Java Code → Compile With Optimization → Machine Code
이렇게 생성된 Native Image는 JVM을 포함하는 Jar와 달리 Java 종속성 없이 단일 실행이 가능하며,
위의 표를 보면 알 수 있듯 우선 한번 빌드된 후 생성된 이미지 파일은 기존 JVM대비 실행소요시간은 50배, 메모리 사용량은 5배 까지 적다고 함
이런 특징은 MSA 환경에서 도커 기반의 환경에서 빈번한 실행과 변경에 적합 - (Redis, MongoDB 연동 환경 기준)
일반 프로젝트 - 5.342 seconds
Native Image - 0.123 seconds
- Native Image의 한계
- 초기에는 AoT 컴파일러에 비해 훨씬 뛰어난 성능을 보인다. 이는 AoT 컴파일러에 의해 만들어진 Native Image는 기계어로 번역되며 그 시점에 최적화까지 진행 하기 때문
하지만 시간이 지나고 요청을 지속적으로 처리 할 수록 JIT 컴파일러가 뛰어난 성능을 보이게 되는데, 이는 애플리케이션을 실행하며 얻어낸 실행 환경 정보를 바탕으로 더욱 합리적인 최적화를 진행하기 때문 - Native Image는 초기 빠른 실행과 처리에 포커스를 맞춤
기존 JIT 컴파일러 생성 파일은 초기 실행은 느리지만 웜업(WarmUp) 과정을 거치면 더욱 안정적인 성능을 보임
- 초기에는 AoT 컴파일러에 비해 훨씬 뛰어난 성능을 보인다. 이는 AoT 컴파일러에 의해 만들어진 Native Image는 기계어로 번역되며 그 시점에 최적화까지 진행 하기 때문
참고 문서
https://endoflife.date/spring-boot
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide
https://stackoverflow.com/questions/77443578/mitigation-after-spring-boot-2-7-eol
https://techblog.lycorp.co.jp/ko/how-to-migrate-to-spring-boot-3
'Spring' 카테고리의 다른 글
[Spring] Junit 테스트시 Atomikos 커넥션풀의 Connection Name 중복 오류 (0) | 2024.07.08 |
---|---|
IntelliJ에서 Spring MVC 세팅하기 (0) | 2024.03.17 |
[JPA] 일대다(1:N), 다대일(N:1) 관계 (0) | 2023.09.03 |
[JPA] 연관관계의 주인 (0) | 2023.09.01 |
[Spring] 서비스 운영간 발생한 DB Connection Closed 이슈 (0) | 2023.08.30 |