스프링부트 멀티 모듈 프로젝트란?

dev-jjun·2023년 8월 13일
0

Server

목록 보기
20/33

🧐 그게 뭐람!?

이제까지 토이프로젝트를 진행할 때나 학교에서 실습을 하는 등 소규모로 진행되는 상황에서 스프링부트 프로젝트를 하나로 관리하는 형태를 많이 봤을 것이다. 하지만 실무에서는 하나의 프로젝트로 서버를 운영하는 일이 거의 드물고 일정 수준 이상의 트래픽을 감당하려면 서버를 구분하는 경우가 훨씬 많다.

단일 프로젝트로는 관리부터 개발 시 파일 접근성의 측면까지 다소 비효율적이라는 한계가 있어, 이를 여러 개의 프로젝트를 통합 구동시키는 방식으로 효율적인 관리가 가능하기 때문이다!

그렇다면 프로젝트를 여러 개로 분리했을 때 코드가 중복되는 부분이 많아질 수 있는데.. 이는 수정사항이 생겼을 때 여러 프로젝트에 공통된 부분을 계속해서 바꿔줘야 하는 번거로움이 따른다.

여러 개의 프로젝트로 분리했을 때 충족시켜야 할 사항은 다음과 같다.

  • 공통된 기능을 담는 코드는 하나의 공통 프로젝트로 관리한다.
  • 공통 프로젝트의 코드를 개발 시에 자유롭게 가져다 쓸 수 있어야 한다.
  • 빌드 시 항상 공통 프로젝트를 포함해야 한다.

즉, 하나의 공통 프로젝트를 두고 여러 프로젝트에서 이들을 공용하는 방식으로 해결할 수 있다! 이를 바로 멀티 모듈 프로젝트라고 한다.

*멀티 모듈을 도입하자!*

멀티 모듈로 구성을 한다면, 하나의 gradle 내에서 여러 개의 프로젝트가 구동되어 최종적으로 하나의 프로젝트처럼 돌아갈 수 있게 된다.

하지만, 여러 개의 프로젝트로 분리해두고 모듈 단위로 구성하여 사용한다는 것 자체가 제대로 모르는 체로 접근했다가 더 복잡한 문제를 초래할 수 있다.

  • 공통 모듈에 코드가 점점 많아져 너무 커지게 된다면?
  • 모듈 간의 의존성이 꼬여 순환참조 에러가 발생할 수 있다!
  • 공통 모듈에서 사용하는 의존성을 하위 모듈에서는 사용하지 않을 가능성이 높다

와 같이 개별 프로젝트마다 다르게 적용되는 설정과 로직이 하나의 모듈로 모이면서 생기는 문제가 더 큰 문제로 이어질 수 있다.

따라서 계층 구조를 명확히 분리하고, 각 모듈이 가진 역할과 책임을 명확히 하여 의존관계를 최소화하는 것이 좋다.

모듈을 어떻게 분리해야 효율적일까?

많은 모듈에서 의존할수록 얇은 의존성을 제공해야 한다.

먼저 모듈의 정의를 살펴보면, 독립적으로 운영될 수 있는 의미를 가지는 구성요소 단위라 한다.

시스템과 무관하게 다른 프로젝트에서도 그대로 가져다 사용할 수 있는 독립성부터 시스템 내에서 영향력을 가지는 범위가 여러 계층에 걸치지 않게 하는 독립성까지 의미를 다양한 의미를 내포하고 있을 것이다. 우리는 먼저 이 독립성을 기준으로 영향을 미치는 범위에 따라 계층을 나누어야 한다.

효율적인 모듈 분리

👩🏻‍💻 직접 해보면서 이해하기

API 서버와 알림 서버를 분리하여 모듈을 import 하여 사용하도록 구성할 것이다.

1. New > Module

프로젝트 최상단에서 우클릭 후, Module 탭을 선택하면 자동으로 settings.gradle 파일에 새로운 모듈이 include된다.

또는 수동으로 settings.gradle**include #{모듈명}**으로 추가해줄 수 있다.

2. build.gradle에서 공통적인 설정 적용

  • 루트 프로젝트에서 한번에 관리
    // build.gradle
    
    subprojects {
    		apply plugin: "org.springframework.boot"
    		apply plugin: "io.spring.dependency-management"
    		apply plugin: "java"
    
    		group = ""
    		version = ""
    		sourceCompatibility = "{java version}"
    
    		repositories {
    				mavenCentral()
    		}
    		
    		configurations {
    				compileOnly {
    						extendsFrom annotationProcessor
    				}
    		}
    		
    		dependencies {
    				// 하위 모듈에서 공통으로 사용할 의존성 라이브러리 세팅
    		}
    }
    
    project(":모듈명") {
    		bootJar { enabled = false }  // 실제 빌드할 jar 파일은 루트 프로젝트에서 만들어지므로 하위 모듈 단위에서는 비활성화 해준다. 
    		jar { enabled = true }   // ~-plain.jar 파일이 함께 만들어지지 않게 하려면 false로 비활성화 해준다. 
    		
    		dependencies {
    				// 하위 모듈 개별에 적용할 의존성 추가
    				compile project(":공통모듈명")  // 특정 모듈의 세팅을 그대로 가져와서 로딩할 수도 있다
    		}
    }
    • subprojects

      setting.gradle에 include된 프로젝트를 전부 관리한다.

      *최상단의 rootproject까지 적용하려면 allprojects로 등록할 수도 있다.

    • project

      하위 프로젝트를 각각 관리한다. 
      
      이때 **공통 프로젝트의 모듈을 각 프로젝트 별로 포함시켜줘야** 모든 프로젝트에서 사용할 수 있다

      → 해당 모듈 간의 설정 구성은 [Gradle > Dependencies > compileClasspath]를 확인하면 된다.

      → 여기서 모듈 간의 의존 관계가 순환참조를 그리지 않도록 하는 것이 중요!

  • 개별 프로젝트에서 각각 설정 API 서버와 알림 서버를 하나로 통합한 루트 프로젝트가 없는 경우에 다음과 같이 설정할 수 있다.
    // server-api/build.gradle
    dependencies {
    		implementation project(":모듈명")
    }
    
    // server-notification/build.gradle
    dependencies {
    		implementation project(":모듈명")
    }
    • 모듈 간 의존관계를 설정하려면 각각의 build.gradle을 다음과 같이 설정한다.

      ```java
      // server-common/build.gradle (공통 모듈)
      bootJar { enabled = false }
      jar { enabled = true }
      
      dependencies {
      		...
      }
      
      // server-module/build.gradle
      bootJar { enabled = false }
      jar { enabled = true }
      
      dependencies {
      		implementation project(":공통모듈명")
      }
      ```

      두 프로젝트의 MainApplication 클래스에는 @SpringBootApplication(scanBasePackages = { “모듈1”, “모듈2”, .. }) 와 같이 어노테이션으로 다른 모듈의 빈 등록까지 모두 이루어지도록 패키지를 지정해준다.

3. 빌드는 항상 root 프로젝트를 기준으로!

root 프로젝트 외에 나머지 프로젝트에서는 gradle 폴더, gradlew 등의 파일이 없고, build.gradle, src 폴더만 존재한다.

*만약 분리한 서버를 통합하지 않았다면 각각 빌드해주면 된다

./gradlew server-api:bootJar
./gradlew server-notification:bootJar

참고한 레퍼런스

[Spring] 멀티 모듈 프로젝트 적용

[Spring] 멀티 모듈 프로젝트 만들기

Gradle 멀티 프로젝트 관리

profile
서버 개발자를 꿈꾸며 성장하는 쭌입니다 😽

0개의 댓글