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
'Kotlin' 카테고리의 다른 글
[JPA] 예상치 못한 N+1 문제 해결하기 (1) | 2024.02.27 |
---|---|
[Spring Boot 3.0 / Spring Security 6.0] Controller에서 시큐리티 인증 mocking 후 테스트 하기(401 피하기) (0) | 2024.01.11 |
중복 데이터로 인한 Single{}의 IllegalArgumentException (0) | 2023.08.23 |
[Kotlin] @PreAuthorize를 사용한 인가(Authorization)처리 (0) | 2023.04.29 |
[Kotlin/Spring Boot] Swagger 3.0 적용하기 (0) | 2023.02.24 |