레시피 12.1 확장을 위해 스프링 관리 빈 클래스 오픈하기

문제

스프링은 개발자가 작성한 클래스를 확장하는 프록시를 생성해야 한다. 하지만 코틀린 클래스는 기본 final이다

해법

확장을 위해 자동으로 필요한 스프링 관리 클래스를 열어주는 스프링 플러그인을 빌드 파일에 추가하자

설명

**프록시와 진짜 객체는 둘 다 같은 인터페이스를 구현하거나 같은 클래스를 확장**한다.

들어오는 요청을 프록시가 가로채고 이 프록시는 서비스가 요구하는 모든 것을 적용한 다음 진짜 객체로 전달한다.

예를 들어 스프링 트랜잭션 프록시는 어떤 메소드 호출을 가로챈 뒤 트랜잭션을 시작한 뒤에 해당 메소드를 호출,

실제 메소드 안에서 일어난 상황에 맞춰 트랜잭션을 커밋하거나 롤백한다

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version PluginVersions.SPRING_BOOT_FRAMEWORK_VERSION
    id("io.spring.dependency-management") version PluginVersions.SPRING_DEPENDENCY_MANAGEMENT_VERSION
    kotlin("jvm") version PluginVersions.JVM_VERSION // 코틀린 JVM 플러그인을 추가
    kotlin("plugin.spring") version PluginVersions.PLUGIN_SPRING_VERSION // 코틀린 스프링 플러그인을 요구
    kotlin("plugin.jpa") version PluginVersions.PLUGIN_JPA_VERSION
    kotlin("kapt") version PluginVersions.KAPT_VERSION
}

group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17

configurations {
    compileOnly {
        extendsFrom(configurations.annotationProcessor.get())
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(Dependency.VALIDATION)
    implementation(Dependency.WEB)
    implementation(Dependency.JACKSON)
    implementation(Dependency.JPA)
    implementation(Dependency.REFLECT) // 소스 코드가 코틀린으로 작성된 경우 필요
    implementation(Dependency.STDLIB_JDK8) // 얘도 똑같음
    implementation(Dependency.SPRING_SECURITY)
    kapt(Dependency.QUERYDSL_PROCESSOR)
    implementation(Dependency.QUERYDSL)
    runtimeOnly(Dependency.MYSQL)
    implementation(Dependency.OPENFEIGN)
    implementation(Dependency.JWT)
    implementation(Dependency.FIREBASE_ADMIN)
    annotationProcessor(Dependency.PROPERTIES_SCAN)
}

kotlin.sourceSets.main {
    kotlin.srcDir("$buildDir/generated/source/kapt/main")
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict") // JSR-305과 연관된 널 허용성 @ 지원
        jvmTarget = "17"
    }
}

tasks.withType<Test> {
    useJUnitPlatform()

}

allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.MappedSuperclass")
    annotation("javax.persistence.Embeddable")
}

noArg {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.MappedSuperclass")
    annotation("javax.persistence.Embeddable")
}

tasks.getByName<Jar>("jar") {
    enabled = false
}