이 글에서는 Git의 submodule을 이용하여 Spring에서 자주 쓰이는 설정 클래스들을 모듈화하여 관리하는 방법을 제시합니다.
Gradle 프로젝트일 경우의 예시입니다.
Spring과 Gradle에 대해 어느정도 지식이 있다는 가정하에 작성된 글입니다.
a-project
현 회사의 A솔루션의 API를 제공하는 Spring 프로젝트를 관리해오다가 B솔루션의 API를 만들어달라는 요청이 왔습니다.
그래서 새로운 프로젝트를 생성하고 API를 만들려고 하는데 기존의 web
, security
, data-jpa
등의 설정을 동일하게 적용하거나 확장하여 적용하려합니다.
a-project
ㄴ WebConfig.java
ㄴ SecurityConfig.java
------------------------
b-project
???
떠오르는 방법이 몇가지 있습니다.
a-project
ㄴ WebConfig.java
ㄴ SecurityConfig.java
------------------------
b-project
ㄴ WebConfig.java
ㄴ SecurityConfig.java
당장은 용이할 수 있으나 추후 프로젝트가 많아질 시 기존 필수 설정의 존재를 파악하지 못하거나 공통 설정값 변경 시 여러 프로젝트를 업데이트 해야하는 등 여러 불편함이 생길 수 있습니다.
설정 관련 클래스와 의존성을 Gradle 모듈로 분리 생성하여 관리합니다.
foo-company
ㄴ a-project
기존 a-project
를 모듈로 분리해 루트 프로젝트에 생성합니다.
foo-company
ㄴ a-project
ㄴ foo-company-config
ㄴ web
ㄴ security
그 후 설정 관련 클래스와 의존성을 모듈로 분리합니다.
여기서 각각 독립적인 기능을 하도록 최소단위로 설정관련 모듈을 생성합니다.
// foo-company-config/build.gradle
dependencies {
...
api 'org.springframework.boot:spring-boot-starter-web'
}
다른 모듈에서 참조할 수 있게 내부 의존성을 api
를 사용하여 열어둡니다.
// a-project/build.gradle
dependencies {
...
api project(':foo-company-config:web')
api project(':foo-company-config:security')
}
a-project
는 foo-companyconfig
의 모듈들을 참조합니다.
foo-company
ㄴ a-project
ㄴ foo-company-config
ㄴ web
ㄴ security
ㄴ b-project
새로 만들 b-project
를 모듈로 추가합니다.
// b-project/build.gradle
dependencies {
...
api project(':foo-company-config:web')
}
b-project
에서는 foo-company-config
의 모듈 중에서 사용 할 모듈을 선택해 참조합니다.
이 방법의 장점은 각 설정 별로 독립된 코드를 가지고 있어 유지보수하기 쉽고 재사용과 확장이 편합니다.
단점은 신규 프로젝트에 설정 모듈을 사용하려면 루트 프로젝트에서 모듈을 생성하고 설정모듈을 참조해야 하는데 신규 프로젝트가 많아지면 루트 프로젝트가 점점 무거워지고 형상관리를 프로젝트 별로 하기 힘들어집니다.
프로젝트는 각각 독립적으로 존재하면서 설정 모듈만 불러올 수 있다면 이러한 단점이 사라지게 됩니다.
Git의 서브모듈을 요약하자면 Git 저장소 안에 다른 Git 저장소를 디렉토리로 분리해 넣는 것입니다.
이 기능을 활용하면 설정 모듈을 Git
으로 관리하면서 다른 repository
에서 불러와 사용할 수 있습니다.
foo-company // 팀 organization
ㄴ a-project // repository
ㄴ foo-company-starter
ㄴ b-project
기존의 모듈들을 별도의 저장소로 등록합니다.
이제 각각의 프로젝트는 별로도 형상관리를 할 수 있으며 필요한 저장소를 서브모듈로 불러올 수 있습니다.
a-project
에 foo-company-starter
저장소를 서브모듈로 등록해봅시다.
git submodule add {submodule_repository_url}
위 명령어를 a-project
의 루트 위치에서 실행합니다. submodule_repository_url
는 서브모듈로 추가할 저장소의 url입니다. 여기서는 foo-company-starter
저장소의 url입니다.
명령어에 대한 상세설명은 공식문서를 참고해주세요.
a-project
...
ㄴ foo-company-starter // 1
ㄴ .gitmodules // 2
명령어가 정상적으로 실행되었다면 다음과 같은 파일과 디렉토리가 추가됩니다.
1. 서브모듈로 추가한 저장소의 폴더
2. 서브모듈 설정 파일
// a-project/.gitmodules
[submodule "foo-company-starter"] // 1
path = foo-company-starter // 2
url = {저장소 url}
서브모듈 설정 파일인 .gitmodules
는 다음과 같이 구성되있습니다.
1. 등록된 서브모듈명
2. 루트기준 해당 서브모듈 상대경로
설정 모듈 저장소는 성공적으로 끌고 왔지만 사용하려면 Gradle 모듈에 포함해야 합니다.
// a-project/settings.gradle
...
include 'foo-company-starter:web'
include 'foo-company-starter:security'
...
사용할 모듈을 settings.gradle
에 include
시키고 Gradle 프로젝트를 다시 로드해주면 해당 모듈을 사용할 수 있습니다.
b-project
에서 또는 새로운 프로젝트에서도 동일하게 작업해주면 됩니다.
Git의 서브모듈은 이러한 응용법 외에도 다양하게 활용할 수 있습니다.
저는 설정 모듈은 최대한 유연하게 작성하여 다양한 프로젝트에서 대응할 수 있게 관리하고 각 프로젝트에서는 해당 프로젝트 성격에 맞게 빈을 재정의하여 사용합니다.
web
, security
, data
외에도 test
, batch
, 외부 api 등 다양하게 모듈을 생성하여 사용합니다.
감사합니다!
좋은 정보 감사합니다.