1. 자동 설정
- 자동 설정(Auto-configuration)은 스프링 부트를 말할 때 빠질 수 없는 핵심기술을 말합니다.
- 이는 개발자들이 스프링 관련 프레임워크나 라이브러리를 추가했을 때 번거로운 설정 없이 동작하도록 최적화된 자동 설정을 내장하고 있는 것을 말합니다.
- 예를 들어 스프링 부트 프로젝트에 스프링 데이터 JPA, 스프링 데이터 몽고디비와 같은 프로젝트를 적용하면 내장 설정이 동작하게 되므로 개발자는 최소한의 설정 값(DB 접속 정보 등)만 넣어주거나 경우에 따라서는 설정을 새롭게 구성할 수 있게 되는 것입니다.
2. 자동 설정 뜯어보기
- 스프링 부트는 애플리케이션을 실행하는 시점에 autoconfigure 모듈 내부의 META-INF 하위에 있는 메타데이터 파일을 우선적으로 검색합니다.
...
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration
...
- 메타데이터 파일 내부에는 자동 설정을 구현한 후보(candidate) 클래스들의 목록이 등록되어 있습니다
- 예를 들어 (jpa.HibernateJpaAutoConfiguration, redis.RedisRepositoriesAutoConfiguration),...
- 스프링 부트는 @EnableAutoConfiguration 애노테이션이 존재하면 자동 설정 클래스를 검색하고 조건에 따라서 자동 설정 클래스를 로드합니다.
- 기본적으로 선언하지 않아도 @SpringBootApplication 애노테이션에 포함되어 있기 때문에 따로 선언할 필요가 없지만 직접 사용할 수도 있습니다.
3. 조건부 애노테이션
- 자동 설정이 많다는 건 해야 할 설정이 적어지기 때문에 매우 편하지만 그렇다고 해서 사용하지도 않는데 모든 설정 클래스를 한 번에 로드하는 것은 너무 불필요한 작업일 것입니다.
- 스프링 부트는 그래서 조건부 애노테이션(Conditional Annotation)인 @Conditiona을 사용해 조건에 따라 자동 설정 클래스를 로드합니다.
- 또한 스프링 부트는 자주 사용하는 조건부 애노테이션을 재사용성을 위해 미리 정의하여 제공하고 있습니다. 이러한 애노테이션은 @ConditionalOn이라는 이름으로 시작합니다.
- autoconfigure 모듈 내부의 ConditionalOn으로 시작하는 애노테이션
- 위와같이 클래스가 존재하는 경우에만 동작하거나 이와 반대로 클래스가 존재하지 않는 경우에 동작하는
- @ConditionalOnClass, @ConditionalOnMissingClass
- 빈이 애플리케이션 컨텍스트에 존재하는 경우에만 동작하거나 이와 반대로 빈이 애플리케이션 컨텍스트에 존재하지 않는 경우에만 동작하는
- @ConditionalOnBean, @ConditionalOnMissingBean
- 다음은 미리 정의된 조건부 애노테이션이 어떤 식으로 사용되는지 알기 위해 스프링의 핵심 기능 중 하나인 AOP 자동 설정 클래스인 AopAutoConfiguration과 @ConditionalOnProperty를 예로 들어 설명합니다.
- 프로퍼티가 존재하는 경우에만 동작하는 ConditionalOnProperty가 적용된 자동 설정 클래스 AopAutoConfiguration
@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration
이제 위 지식을 바탕으로 직접 커스텀 스프링 부트 스타터를 만들어 보도록 하겠습니다.
- 스프링 부트 스타터(spring-boot-starter)는 스프링 부트 기반의 애프리케이션에 따른 스프링 프로젝트를 쉽게 추가할 수 있도록 만들어진 라이브러리를 말합니다.
- 각각의 스타터에는 주축이 되는 스프링 프로젝트와 프로젝트에서 필요로 하는 필수적인 라이브러리들이 포함되어 있습니다.
- 이런 이유로 스프링 부트 스타터를 사용하면 스타터 외에 필요한 라이브러리를 따로 추가하거나 관리할 필요가 없습니다.
보통 서드 파티 스프링 부트 스타터의 명명은 *-spring-boot-starter와 같은 방식으로 명명하는 것이 일반적입니다.
커스텀 스프링 부트 스타터 만들기
지금부터 직접 만들어본 handgame 라이브러리와 스프링 부트의 기능을 사용해서 커스텀 스프링 부트 스타터를 만들어 보도록 하겠습니다.
- 우리는 그래이들의 멑리 프로젝트를 사용해서 하나의 프로젝트에 멀티 모듈을 구성했습니다.
- 생성된 멀티 모듈의 구조는 아래와 같습니다.
- handgame
- 가위바위보 게임의 상세 구현이 포함된 라이브러리
- handgame-spring-boot-autoconfigure
- handgame 라이브러리의 자동 설정이 포함
- handgame-spring-boot-starter
- handgame, handgame-spring-boot-autoconfigure를 합친 커스텀 spring-boot-starter
- handgame-sprint-boot-app
- handgame-spring-boot-starter를 사용하는 스프링 부트 애플리케이션
- handgame
최상위 build.gradle.kts
import org.springframework.boot.gradle.plugin.SpringBootPlugin
plugins {
id("org.springframework.boot") version "2.7.0" apply false
id("io.spring.dependency-management") version "1.0.11.RELEASE"
id("maven")
id("maven-publish")
kotlin("jvm") version "1.6.21"
kotlin("plugin.spring") version "1.6.21"
kotlin("kapt") version "1.6.21"
}
allprojects {
group = "com.fastcampus.springboot"
version = "1.0-SNAPSHOT"
repositories {
mavenLocal()
mavenCentral()
}
}
...
- maven-publish는 메이븐 리파지토리에 배포할 수 있게 하는 기능을 하는 플러그인입니다. 이번 예시에서는 제작한 스타터 프로젝트를 로컬 메이븐 리파지토리에 배포해서 handgame-spring-boot-app에서 사용해보도록 하겠습니다.
- allprojects는 최상위 프로젝트를 포함한 전체 프로젝트에서 사용하는 빌드를 구성합니다.
- subprojects는 settings.gradle.kts레서 include에 감싸진 프로젝트의 빌드를 구성합니다. 예를 들면 include("handgame", "handgame-spring-boot-starter)와 같은 프로젝트가 서브 프로젝트입니다.
handgame/Handgame.kt
handgame-spring-boot-autoconfigure/build.gradle.kts
- kapt는 코틀린의 애노테이션 프로세서입니다. 이는 컴파일 타임에 애노테이션을 읽어서 동적으로 코드를 생성하거나 변경하는 등의 기능을 말하는데 kapt는 코틀린 언어에서 이러한 애노테이션 프로세서가 동작하도록 하는 플러그인입니다.
- 자동 설정 클래스에서 Handgame.kt클래스를 불러올 수 있어야 하기 때문에 handgame프로젝트에 대한 의존성을 추가합니다.
- spring-boot, spring-boot-autoconfigure는 우리가 만들 자동 설정이 스프링 부트 자동 설정 기능을 사용해야 하므로 필수적인 의존성임
handgame-spring-boot-autoconfigure/HandgameAutoconfigure.kt
package com.fastcampus.springboot.autoconfigure.handgame
import com.fastcampus.springboot.handgame.Handgame
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.context.annotation.Bean
@Configuration
@ConditionalOnClass(Handgame::class)
@ConditionalOnProperty(prefix = "my.handgame", name = ["enabled"], havingValue="true")
class HandgameAutoconfiguration {
@Bean
@ConditionalOnMissingBean
fun handgame() = Handgame()
}
- HandgameAutoconfiguration은 Handgame클래스의 인스턴스를 스프링 빈에 등록하는 자동 설정 클래스입니다. 자동 설정 클래스는 설정 클래스임을 나타내기 위해 @Configuration어노테이션을 선언합니다.
- @ConditionalOnProperty를 사용해서 my.handgame으로 시작하고 enabled라는 프로퍼티가 true인 경우에만 해당 설정 클래스가 동작하도록 로드 시점을 조절합니다.
- 만약 사용자가 handgame 빈을 재정의한 경우에는 충돌이 일어날 수 있으므로 @ConditionalOnMissingBean을 사용해서 handgame빈이 존재하지 않는 경우에만 빈을 로드합니다.
handgame-spring-boot-autoconfigure/META- INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.fastcampus.springboot.autoconfigure.handgame.HandgameAutoconfiguration
- 그리고 우리가 작성한 자동 설정 클래스 handgameAutoConfiguration을 스프링에게 알려주기 위해 해당 파일에 명시해야 합니다.
handgame-spring-boot-starter/build.gradle.kts
dependencies {
api(project(":handgame"))
api(project(":handgame-spring-boot-autoconfigure"))
}
- 앞서 구현한 handgame 라이브러리와 자동 설정 구현체인 handgame-spring-boot-autoconfigure에 대한 의존성을 추가합ㅂ니다.
그리고 handgame > handgame-spring-boot-autoconfigure > handgame-spring-boot-starter 순서로 jar파일로 배포합니다.
handgame-spring-boot-app/build.gradle.kts
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("com.fastcampus.springboot:handgame-spring-boot-starter:1.0-SNAPSHOT")
}
- 배포가 완료됐다면 스타터를 사용할 프로젝트에 의존성을 추가해줍니다.
정상 작동합니다. 그리고 git주소는 아래에 첨부합니다.
https://github.com/eunoiahyunseo/kotlin-thirdparty-module-starter-app
'Web > Kotlin & Spring' 카테고리의 다른 글
[Kotlin & Spring] - TODO 서비스에 코틀린 도입해서 리팩토링 하기 + Test Double (0) | 2023.06.28 |
---|---|
[Kotlin & Spring] - 자바 프로젝트에 코틀린 도입하기 (0) | 2023.06.28 |
[Kotlin & Spring] - 코틀린 문법 고급 (0) | 2023.06.25 |
[Kotlin & Spring] - 코틀린의 기본 문법 (0) | 2023.06.23 |
[Kotlin & Spring] - 코틀린의 소개 (0) | 2023.06.23 |