Kotlin
[Kotlin, Spring, JPA] Boilerplate 프로젝트 만들기
keep it simple
2023. 2. 20. 04:30
Boilerplate란?
- 단순한 반복작업을 없애주고 생산성을 향상시켜주는 작업을 Boilerplate라 한다. 우리가 흔히 아는 보일러가 맞다. 보일러의 통은 보일러를 만드는데 무조건 필요하다. 기능만 업그레이드할 뿐 플레이트는 계속 찍어낸다. 개발에서 이런 보일러 통 생산같이 단순한 반복작업은 없앨수 있으면 무조건 없애는게 좋다.라이브러리의 버전은 달라질 수 도 있으나 구조는 비슷하므로 Koltin,Spring,JPA로boilerplate 프로젝트를 만들어보자!
1. https://start.spring.io/ 에서 밑과 같이 의존성 설정 후 생성 (DB는 취향껏, java 11버전이라 스프링 부트 버전 2.7.8로 선택했다. - 스프링 부트 3.0 버전 이상은 자바 17버전으로만 사용 가능)
2. build.gradle에 밑과 같이 추가하여 이미지처럼 맞춘다.
plugins {
kotlin("plugin.allopen") version "1.6.21"
}
noArg{
annotation("javax.persistence.Entity")
}
allOpen{
annotation("javax.persistence.Entity")
annotation("javax.persistence.Embeddable")
annotation("javax.persistence.MappedSuperclass")
}
- noArg : @Entity가 달린 엔티티 클래스에 기본 생성자를 생성해주기위에 noarg 플러그인 사용 - 만약 이 플러그인을 적용안하면 컴파일 에러는 발생을 안하지만 쿼리가 날라갈 때 에러가 발생한다.
- allOpen: JPA 구현체인 Hiberate는 지연로딩(Lazy Loading)을 사용할 때 CGLIB를 사용해서 프록시 객체를 만든다. 하지만 코틀린은 모든 클래스가 final 속성(final 클래스는 프록시 객체를 생성하지 못한다.)이기 때문에 allopen 플러그인을 통해 제거해야한다. -만약 이 플러그인을 적용안하면 즉시로딩(Eager Loading)으로 사용되서 불필요한 쿼리가 나가서 서버 성능이 저하된다.
3. 공통으로 엔티티에 사용할 BaseEntity 클래스 생성하기
@MappedSuperclass
@EntityListeners(AuditingEntityListener::class)
abstract class BaseEntity {
@Id
@GeneratedValue
val id: Long = 0
@CreatedDate
@Column(nullable = false, updatable = false)
protected var createdAt: LocalDateTime = LocalDateTime.MIN
@LastModifiedDate
@Column(nullable = false)
protected var updatedAt: LocalDateTime = LocalDateTime.MIN
}
package com.project.boilerplate.domain
import com.project.boilerplate.infrastructure.persistence.BaseEntity
import javax.persistence.Entity
import javax.persistence.Table
@Entity
@Table(name = "member")
class Member(
val name: String
): BaseEntity() {
}
- 위처럼 BaseEntity생성후 Member 엔티티처럼 상속받으면 된다. 직접적으로 BaseEntity클래스만 사용할일은 없기에 추상화 클래스로 생성
- @MappedSuperclass는 공통 매핑 정보로 사용된다. 위와 같이 createdAt(생성일)/ updatedAt(수정일)은 어떤 Entity든 같이 사용해야되서 해당 어노테이션을 사용했다.
- @EntityListeners(AuditingEntityListener::class)는 Entity에 상태가 변경될 때마다 이벤트 발생시켜주는 어노테이션
- @Id 는 엔티티의 primary key인지 알려주는 어노테이션이다
- @GeneratedValue 는 기본 키를 자동 생성하게 해주는 옵션
- @CreatedDate은 생성 시간을 자동 저장하게해준다.
- @LastModifiedDate은 수정 시간을 자동 저장하게 해준다.
4. 메인 클래스에 @EnableJpaAuditing 붙혀서 auditing 활성화
@EnableJpaAuditing
@SpringBootApplication
class BoilerplateApplication
fun main(args: Array<String>) {
runApplication<BoilerplateApplication>(*args)
}
DDD Layered 아키텍처 적용
계층들 순서는 밑처럼 진행된다.
- presentation: 사용자 UI나 클라이언트 request/response 해주는 계층. 흔히 controller라고 한다.
- application: 비즈니스 로직 정의. 도메인 계층과 인프라 계층을 연결하는 계층이다. 흔히 service라고 한다.
- domain: 실질적으로 도메인에 대한 정보이며 도메인에 대한 모든 책임을 지는 계층. 흔히 entity라고한다.
- infrastructure: 외부와의 통신을 담당하는 계층
- config: 설정 관련
- persistence: jpa관련 repository 관련
장점
- 간단하다. 한 눈에 파악하기 쉽다. -> 유지보수가 쉽다.
- 일관성이 있다.
- 위처럼 각 계층마다 관심사가 분리되어 loosely coupling(느슨한 결합)된 형태다.
결론
- 위처럼 필수적인 기본 세팅만 해놨다. 이후 필요한 부분이나 공통적으로 사용하는 부분은 추가할 예정이다. 위에 layered 아키텍처를 선택한 이유는 현재 DDD 책을 공부하고 있기도 해서 토이프로젝트에 적용해 보려고 만들었다.
reference