
백엔드
SpringBoot
Java를 기반으로 한 웹 어플리케이션 프레임워크이며, 최소한의 초기 스프링 구성으로 가능한 한 빨리 시작하고 실행할 수 있도록 설계되었다.
Github Stars : ★ 76629
사용 기업

트렌비

플렉스

렌딧

토스랩

핀다

드라마앤컴퍼니

딜리셔스

뤼이드

식스샵

클래스101

마이리얼트립

와디즈

버즈빌

마켓컬리

쏘카

오피지지

카카오페이

카카오스타일
더 보기
마켓컬리
하이버네이트의 시간은 거꾸로 간다
하이버네이트의 시간은 거꾸로 간다스프링부트 버전을 업그레이드하는 과정에서 발견된 버그 해결기• 문제 좁히기• 1. 배포 전후로 나노초 값이 다른 이유• 의심 1: 자바 버전 업그레이드의 영향 (11 ➡️ 17)• 의심 2: 하이버네이트 버전 업그레이드의 영향 (5.6.5 ➡️ 6.5.5)• 2. 조회 과정에서 음수의 나노초가 발생하는 이유저희 딜리버리 프로덕트 개발팀은 AWS MSK 버전 업그레이드에 대응하기 위해 관리 중인 시스템들의 스프링부트 버전을 3.x대로 업데이트했습니다. 이미 다른 프로젝트에서 스프링부트 버전업을 경험한 데다, 팀원들이 겪었던 이슈들을 잘 정리한 문서 덕분에 큰 어려움 없이 작업을 진행할 수 있었습니다. 업데이트된 프로젝트는 QA를 무사히 통과해 운영 환경에 배포되었고, 배포 후에도 별다른 문제 없이 잘 동작하는 듯했습니다.하지만 다음 날 자정 직전에 에러 알림이 발생하기 시작했습니다. 해당 버그로 인해 일부 배송 매니저는 배송 업무를 볼 때, 사용하는 컬리버드 앱에 로그인 자체가 불가능한 상태였습니다. 특히 에러가 발생한 시점이 샛별 배송이 활발하게 진행되는 시간대였기 때문에, 배송 업무에 차질이 없도록 신속하게 롤백을 진행한 후 다음날 에러 원인을 파악하기 시작했습니다.먼저 문제의 원인을 좁히기위해서 에러 로그를 확인했습니다.이 로그를 통해, DB에서 데이터를 조회하여 객체로 변환하는 과정에서 DateTime 형식에 문제가 있음을 파악할 수 있었습니다. 음수의 나노초 값을 가지는 데이터가 원인인 것 같아서, DB에 그런 데이터가 있는지 확인해보았습니다.하지만 확인 결과, 음수의 나노초를 포함한 날짜나 시각 데이터는 존재하지 않았고, 모든 데이터가 0 또는 양수 값을 가지고 있었습니다.데이터를 검토하면서 배포 이전과 이후의 시점에서 나노초 값이 미묘하게 달라졌다는 점을 발견했습니다. 배포 이전의 데이터에는 나노초가 없었으나, 배포 이후에는 나노초가 포함된 데이터가 생긴 것이었습니다.이로 인해 두 가지 의문이 생겼습니다• 배포 전후로 나노초 값이 다른 이유는 무엇일까?• DB에는 정상 범위의 나노초가 저장되어 있는데, 왜 조회 과정에서 음수의 나노초가 발생하는 걸까?1. 배포 전후로 나노초 값이 다른 이유의심 1: 자바 버전 업그레이드의 영향 (11 ➡️ 17)배포 전후의 차이점을 분석하던 중, 먼저 자바 버전의 변경을 의심했습니다. 스프링 부트 3.x는 최소 JDK 17을 요구하므로, 자바 버전을 11에서 17로 업그레이드했고, 이로 인한 영향을 고려해 LocalTime 로직의 변화를 확인해봤습니다. 하지만 자바 11과 17의 LocalTime 로직에 수정된 부분은 없었습니다.또한, 로컬 환경에서 테스트한 결과, 배포 이전에도 나노초 값은 0이 아닌 상태였으며, 저장 시점에 나노초 값을 버리고 DB에 저장된다는 사실을 알게 되었습니다.의심 2: 하이버네이트 버전 업그레이드의 영향 (5.6.5 ➡️ 6.5.5)자바 버전이 원인이 아닌 것으로 확인된 후, DB 저장을 처리하는 하이버네이트 로직을 의심했습니다. 실
java
spring
springboot
SK텔레콤
SpringBoot 단위/통합 테스트 환경 사례
SpringBoot 는 기존 Spring 의 복잡한 의존성 관리와 설정 부분을개발자가 SpringBoot 에서 대신 관리해줄 수 있는 자동설정 기능을 포함하고 있어서 많이 사용하고 있는 프레임 워크 중 하나 입니다.보통 애플리케이션 개발을 할 때 한정된 예산과 짧은 개발 기간으로(어쩔 수 없는 숙명이죠 ㅠㅠ),비지니스 로직에 집중하기 때문에 마지막 테스트 단계에서 예상치 못한 난관에 봉착할 수 있습니다.TDD(test-driven development) 가 좋은 개념이기는 하지만 TDD를 제대로(?) 도입하기도 여러가지 어려운 점이 있습니다.이번 블로그에서는 SpringBoot 에서 제공하는 테스트 방법을 간략하게 소개하는 시간을 가지려고 합니다.SpringBoot 2.2 버전 이후로 JUnit5가 기본 테스트 의존성으로 설정이 되어 있습니다.아래는 SpringBoot 3.2 버전을 Maven 으로 구성한 프로젝트의 POM 의 일부이며, spring-boot-starter-web 이 포함되 있는 것을 볼 수 있습니다.기본으로 설정되기 때문에 별도로 설정할 필요는 없습니다. 위의 의존성에는 아래의 종속성이 포함되어 있습니다.테스트방법은 여러가지가 있겠지만, 크게 두 가지로 볼 수 있겠습니다.Spring Boot 에서 테스트 코드에 아래와 같이 @SpringBootTest 라는 어노테이션을 작성하면,스프링 부트의 메인 진입점을 포함한 모든 하위 Scope 의 빈(Bean)들을 ApplicationContext 에 등록해 줍니다.따라서 모든 코드를 테스트할 수 있는 통합 테스트를 할 수 있습니다.아무래도 전체를 테스트하다보니 부담이 될 수 있습니다.이럴 때는 @WebMvc 어노테이션으로 원하는 controller 만 테스트 할 수 있습니다.다만, 이런 단위 테스트의 경우에는 service, repository 등과 의존성이 끊기기 때문에 해당 의존성들을 @MockBean 으로 모킹 해줘야 합니다.먼저 간단한 통합테스트를 해보도록 하겠습니다.WebMVC 통합테스트를 할 때 서블릿 컨테이너를 목업 해서 테스트해주는 환경으로 테스트 해보겠습니다.이 때 @AutoConfigureMockMvc와 MockMvc 를 autowired 해 줘야 합니다.UserController.class 와 UserService.class 가 있다고 가정합니다.위의 코드에서는 Servlet 을 목업 해줬기 때문에 테스트 코드에서는 실제 서블릿을 테스트한 것이 아니고,목업 된 서블릿을 테스트 했다고 보시면 됩니다.그런데, 실제 서블릿 환경에서 테스트가 필요할 수도 있습니다.이 경우에는 서블릿 컨테이너를 구동시키고 테스트 해야 하며 아래와 같이 webEnivironment 에 RANDOM_PORT 또는 DEFINED_PORT 를 지정해 줘야 합니다,실제 서블릿 컨테이너이기 때문에 Rest API 로 테스트를 해 줘야 합니다.두 가지 방법이 있는데• None TestRestTemplate 을 의존성 주입 해주고(@Autowired) 리턴 값을 테스트 해 줍니다.WebTestCl
spring
springboot
SK텔레콤
SpringBoot 으로 MSA 구현하기(4)
Spring Web MVC 에서 살펴볼 기능은 다음과 같다. (1편 , 2편)• None pom.xml 에 필요한 라이브러리 설정파일 업로드는 로 쉽게 핸들링이 가능하다.객체에는 파일명, 파일사이즈, 파일 내용 등의 정보를 갖고 있어서 파일을 다루는데에는 매우 편리하다.패키지의 를 쓰면 inputstream 을 File 로 쉽게 쓸 수 도 있다.파일을 디렉토리에 저장하기 위해서는 고유의 파일명이 필요하다. 여기서는 로 되어 있지만 매번 random 하게 생성할 필요가 있다.파일 다운로드는 패키지의 를 사용하여 쉽게 구현할 수 있다.다만, 헤더에 필요한 값들만 추가로 전달해 주면 된다.다운로드는 로도 쉽게 구현할 수 있다.의 속성 중에 가 있다.다운로드 하는 파일이 어떤 타입 인지를 알려주는 것인데 여러타입을 넣을 수 있다.이를 세팅하면 에 설정하지 않아도 정상적으로 파일을 다운로드 할 수 있다.에서는 사용자의 요청을 제일 먼저 처리할 수 있는 를 제공한다.Filter 를 사용하는 비즈니스 로직 중에 가장 일반적인 것은 사용자가 인증을 받았는지 체크하는 로직이다.이와 비슷하게 SpringBoot 에서는 를 지원한다.Filter 와 Interceptor 는 모두 SpringBoot 이 인식할 수 있는 등록 과정이 필요하다.이러한 등록 과정은 으로 등록하는 방법과 Design Pattern 중에 이 사용된 의 특정 메소드를 구현하는 방법이 있다.Filter 는 Bean 으로 등록하면 바로 사용 가능하다.로 Bean 으로 등록하고 로 Bean 의 순서를 지정할 수 있다.메소드의 앞 뒤로 필요한 전처리, 후처리 작업을 할 수 있다.혹은 아래와 같이 메소드에 어노테이션을 사용해서 Bean 을 만들 수 도 있다. 물론 이 때는 바로 Bean 을 사용하는 것이 아니라 을 사용해서 등록한다.인터페이스를 구현하여 Bean 을 만들어서 사용했다.Interceptor 는 인터페이스를 구현한다.단, interceptor 의 메소드를 통해서 할 수 있다.서로 다른 호스트 주소가 다를 때 요청을 허용하는 CORS 는 를 사용하면 쉽게 등록할 수 있다.모든 url 매핑을 허용하고 도메인만 예외로 적용하면 이 때 사용 가능한 HTTP method 지정이 가능하며,클라이언트가 pre-flight request 결과에 대한 캐싱하는 시간을 초 단위로 세팅한다.환경 파일과 관련하여 제공하는 기본 파라미터인 가 있다. 이 값은 기본 값이 이며,자바 어플리케이션을 실행할 때 환경 변수 파라미터로 지정하는 옵션과 같이 사용한다.프로파일 변수 값에 따라 해당 프라퍼티가 로딩된다.예를 들어 위와 같이 값을 가지면 파일이 로딩된다.가 되는 기본 디렉토리는 이므로 이곳에 properties 파일을 위치 시킨다.application.properties 는 다음과 같다.단순히 서버 포트를 으로 변경하기만 했다.application-dev.properties 는 다음과 같다.값은 지정하지 않았지만 dev 프로퍼티에 없으면 default 프로퍼티를 찾기 때문에 서버 포트는 을 사용한다.라이브
springboot
SK텔레콤
Spring Data를 이용한 SpringBoot 데이터베이스 자동 초기화
Spring Boot와 Spring Data JPA를 사용하면 데이터베이스의 초기 DDL과 DML을 간단하게 수행할 수 있는데, 이를 이용하여 데이터베이스를 생성하고 테이블을 만들고 데이터를 삽입하는 방법을 설명한다. 또한, docker-compose를 통해 MySQL을 설치하고 데이터 소스 환경 설정을 하고, DDL과 DML을 자동화하는 방법도 소개한다. 이를 통해 개발 환경에서의 설정이 용이해지고, 실제 프로덕션 환경에서는 동작하지 않도록 주의해야 한다.• None 가끔 프로그램을 개발할때 데이터베이스 생성, 테이블생성, 데이터 인서트등을 초기에 수행해야하는 경우가 있다.• None 이때 SpringBoot + Spring Data JPA를 이용하면 쉽게 초기 DDL과 DML을 수행할 수 있다.• None https://start.spring.io 에 접속하여 다음과 같이 프로젝트를 생성하자.• None 우선 Mysql을 이용할 것이고, mysql 서버 설치가 필요하다.• None 우리는 여기서 간단하게 docker-compose를 이용하여 mysql을 설치할 것이다.• None docker-compose.yaml 파일을 생성하고 다음과 같이 작성하자.• None docker-compose.yaml 파일의 내용은 다음과 같다.• None platform: mac m1 칩을 이용하는 경우라면 'linux/arm64' 를 지정한다. 그렇지 않다면 제거해도 된다.• None restart: always 는 인스턴스가 내려가면 자동으로 재 시작 하라는 의미가 된다.• None volumes: 볼륨을 지정한다. <호스트볼륨>:<컨테이너내부 볼륨> 을 의미한다.• None ports: 포트를 지정한다. <호스트 포트>:<컨테이너 내부 포트> 을 의미한다.• None 데이터베이스의 데이터소스 환경 설정을 수행하자.• None application.yaml 파일에 다음 내용을 추가하자.• None DDL 은 데이터베이스 생성이나, 테이블 생성을 위한 쿼리 파일이다.• None resources/schema.sql 파일을 생성하고 다음과 같이 작성한다.• None CREATE TABLE 구문은 테이블을 생성한다.• None IF NOT EXISTS 구문은 테이블이 존재하지 않는경우 테이블을 생성한다.• None 위 쿼리는 스프링부트가 기동될때 생성하고자 하는 테이블 스키마 정보이다.• None 자동 DML 수행을 위한 환경 설정은 다음과 같다.• None 위와 같이 generate-ddl 값을 true로 설정하면 자동으로 테이블 생성등의 DDL 작업을 수행한다.• None hibernate.ddl-auto 값은 다음과 같이 지정이 가능하다.• None create: 기존 테이블을 삭제하고 다시 생성한다.• None create-drop: create와 동일하나, 종료 시점에 테이블을 제거한다.• None validate: 엔터티와 테이블이 정상 매핑된 것인지만 확인한다.• None none: 엔터티를 통한 자동생성을 사용하지 않고, schema.sq
docker
mysql
spring
springboot
연관 기술 스택

Java

Spring