일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 리눅스
- resilience4j
- spring
- SQL
- hyperledger
- 초대장
- 자바 프로젝트
- 운영체제
- c#
- 알고리즘
- oracle
- 프로젝트
- 티스토리
- 파이썬 소스
- 오라클 디비
- gradle
- 오라클
- dynamic query
- smart cast
- 문법 정리
- auto configure
- K6
- 자바
- JVM
- 학점
- 유사코드
- 파이썬
- MongoDB
- jsp
- 백준 알고리즘
- Today
- Total
모종닷컴
Mapper 성능 비교 본문
헥사고날 아키텍처 설계에 따라 프로젝트를 하다 보니 각 영역에 전달해 줄 때 데이터 매핑 작업이 필수가 되었습니다. 데이터 매핑을 할 때 쓰는 라이브러리나 함수들이 많은데 각각의 성능을 비교해보고자 합니다.
테스트에 사용할 클래스 생성
data class Food(
var name: String = "",
var price: Int = 0,
var calories: Int = 0,
var color: String = "NONE"
)
data class FoodDto(
var name: String = "",
var price: Int = 0,
var calories: Int = 0,
var color: String = "NONE"
)
ModelMapper
implementation("org.modelmapper:modelmapper:3.1.1")
위 디펜던시 지정해준상태에서 시작하겠습니다.
테스트 코드를 만들고 실행해보도록 하겠습니다.
@Test
fun modelMapperTest() {
val modelMapper = ModelMapper()
val food = Food("치킨", 20_000, 2_000, "RED")
for (i in 1..10_000_000) {
modelMapper.map(food, FoodDto::class.java)
}
}
13초 22가 소요되었습니다.
Spring BeanUtil
프로퍼티 복사에 사용되는 것중에 BeanUtil이라는 것이 있습니다. 이 유틸클래스를 통해서 테스트를 진행해 보도록 하겠습니다.
@Test
fun springBeanUtilsTest() {
val food = Food("치킨", 20_000, 2_000, "RED")
for (i in 1..10_000_000) {
val dto = FoodDto()
BeanUtils.copyProperties(food, dto)
}
}
17초 191가 소요되었습니다. Model Mapper보다 낮은 성능을 보이고 있습니다.
MapStruct
map struct는 설정이 참 귀찮네요.. 아래처럼 kapt 플러그인 추가해줘야 한다고 합니다. kapt 플러그인에 대해 궁금할 수 있는데 kapt는 코틀린 어노테이션 프로세서를 실행하기 위한 Gradle 플러그인입니다. 코틀린 코드에 대해서 코드 생성 및 변환을 수행할 수 있습니다. 즉, 코틀린 어노테이션 프로세서를 사용하면 코드를 자동으로 생성할 수 있습니다. MapStruct는 내부적으로 코드 생성기를 사용한다고 하는데 그래서 이 Kapt가 필수로 설정이 되어야 하는 것 같습니다.
plugins {
kotlin("jvm") version "1.6.21"
kotlin("kapt") version "1.6.21"
}
dependencies {
implementation("org.mapstruct:mapstruct:1.5.3.Final")
kapt("org.mapstruct:mapstruct-processor:1.5.3.Final")
}
그레이들에 설정을 하였으면 다음으로는 Mapper 인터페이스 클래스를 만들어줘야 합니다.
@Mapper
interface FoodMapper {
@Mappings
fun toDto(food: Food): FoodDto
companion object {
val INSTANCE: FoodMapper = Mappers.getMapper(FoodMapper::class.java)
}
}
이렇게 인터페이스로 정의된 FoodMapper는 그레이들이 빌드하면서 kapt를 이용하여 Implement 클래스를 만들어주게 되는 건가 보네요. 따라서 빌드를 돌린 이 후에 build/generated 폴더로 들어가 보면 생성된 코드가 보입니다.
@Test
fun mapStructTest() {
val food = Food("치킨", 20_000, 2_000, "RED")
for (i in 1..10_000_000) {
FoodMapper.INSTANCE.toDto(food)
}
}
테스트 코드를 실행해보겠습니다.
음.. 이래도 되는 건가 싶은데 15ms 시간이 소요되었습니다.
Handmade
손으로 직접 작성을 해보겠습니다. 아래처럼 Util 클래스를 하나 작성해 줍니다.
object FoodMapperUtil {
fun toDto(food: Food) = FoodDto(
name = food.name,
price = food.price,
calories = food.calories,
color = food.color
)
}
@Test
fun manualMappingTest() {
val food = Food("치킨", 20_000, 2_000, "RED")
for (i in 1..10_000_000) {
FoodMapperUtil.toDto(food)
}
}
바로 테스트를 해보면
13 ms 밖에 소요가 안됩니다.
결과 요약
전체 테스트를 한 번에 돌렸을 때 결과를 보았습니다. SpringBeanUtils, ModelMapper는 상당히 느린 모습을 보이고 있고, MapStruct와 수동으로 매핑해 주는 성능은 동일해 보입니다. 만약 매핑해야 하는 클래스가 단순한 구조와 적은 필드를 보유하고 있다면 수동으로 매핑 유틸을 만들어주는 게 훨씬 이득일 것 같고, 복잡한 구조를 지닌다면 MapStruct를 고민해 봐도 좋을 것 같습니다.
'Programming > Spring' 카테고리의 다른 글
spring boot r2dbc + flyway (0) | 2023.06.24 |
---|---|
mysql Insert lock wait timeout 조정해보기 with Spring (1) | 2023.04.23 |
Spring Shell을 이용해 나만의 CLI를 만들어보자 (0) | 2023.01.23 |
Spring에서 Redis에 동적데이터 저장하기 (2) | 2023.01.14 |
SQS 메시지 Polling 컨트롤하기. (0) | 2022.12.04 |