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

mallin·2022년 1월 11일
26

spring

목록 보기
2/4
post-thumbnail

❗️ 멀티 모듈 프로젝트가 필요한 이유

예를 들어서 회원 프로그램을 개발한다고 했을 때 여러 개의 서버가 필요하다.
① batch 서버
② API 서버
등등

하지만 해당 서버들을 단일 프로젝트로 만들게 되면 다음과 같은 문제가 생긴다.

첫번째, 공통적으로 처리해야하는 코드의 처리
: 아예 분리되어 있는 프로젝트이다 보니 공통되는 코드들은 각 프로젝트에 복붙해서 사용할 수 밖에 없고, 한 파일의 코드가 수정되는 경우 다른 프로젝트의 코드도 수정해줘야 한다.

두번째, 접근성 문제
: 프로젝트 수에 따라 IDE 를 실행시켜야 하고 ,, 프로젝트 수가 많아지면 많아 질 수록 개발하는데 어려움이 동반 될 수 밖에 없다.

이런 문제를 해결하기 위해선 멀티 모듈 프로젝트를 사용하면 된다.

❓ 멀티 모듈 프로젝트의 구성


위에서 예시를 들었던 회원 프로그램을 예시로 들자면 위의 그림과 같다.
batch-server module 엔 배치 서버 관련 코드
api-server module 엔 API 관련 코드들이 있다.

두 모듈에서 공통되는 코드는 commons 모듈에 있고 batch-server module 과 api-server module 에서 의존성을 설정해서 사용하는 방식으로 멀티 모듈 프로젝트를 구성할 수 있다.

🏃‍♂️ 멀티 모듈 프로젝트 시작하기

1. 프로젝트 생성


예제에서는 Gradle, 자바 버전은 1.8 로 프로젝트를 생성해주겠다.


프로젝트 생성을 하게 되면 위와 같은 구조가 되는데 우리는 하나의 프로젝트에 여러개의 모듈이 위치해 있고 공통 코드 같은 경우도 따로 모듈에 들어갈 거기 때문에 src 폴더는 삭제해준다.

➡️ 루트 프로젝트는 하위 모듈을 관리하는 역할 만 하 때문에 src 폴더를 삭제해도 괜찮다.

2. 모듈 추가

가장 상위 프로젝트에서 마우스 오른쪽 클릭을 하고, New > Module 을 선택 후, 모듈 이름을 입력해서 모듈을 만들어준다.

해당 프로젝트에서는 velog-api-server, velog-batch-server, velog-core 로 총 3개를 만들어줬다.

velog-api-server : API 관련 모듈
velog-batch-server : Batch 성 관련 모듈
velog-core : velog-api-server, velog-batch-server 에서 사용하는 공통 모듈

setting.gradle 에 새로 만들어진 모듈에 대해서 코드를 추가해줘야 하는데, New > Module 을 통해서 모듈을 만든 경우에는 인텔리제이가 자동으로 코드를 넣어준다.

만일 코드가 없는 경우에는 include #{모듈명} 으로 추가해주자.

3. 프로젝트 세팅

build.gradle 설정

buildscript {
    ext {
        springBootVersion = '2.6.2'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
        classpath "io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE"
    }
}

// 하위 모든 프로젝트 공통 세팅
subprojects {
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'io.spring.dependency-management'

    group 'org.example'
    version '1.0-SNAPSHOT'

    sourceCompatibility = '1.8'
    targetCompatibility = '1.8'
    compileJava.options.encoding = 'UTF-8'

    repositories {
        mavenCentral()
    }

    // 하위 모듈에서 공통으로 사용하는 세팅 추가
    dependencies {
        compileOnly 'org.projectlombok:lombok'

        annotationProcessor 'org.projectlombok:lombok'
        annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
    }

    test {
        useJUnitPlatform()
    }
}

project(':velog-core') {
    // 공통 코드

    bootJar { enabled = false } // core 은 bootJar 로 패키징 할 필요 없음
    jar { enabled = true }

    dependencies {
    }
}

project(':velog-api-server') {
    bootJar { enabled = true }
    jar { enabled = false }

    dependencies {
        compile project(':velog-core') // 컴파일 시 velog-core project 로딩
        implementation 'org.springframework.boot:spring-boot-starter-web'
    }
}

project(':velog-batch-server') {
    bootJar { enabled = true }
    jar { enabled = false }

    dependencies {
        compile project(':velog-core') // 컴파일 시 velog-core project 로딩
    }
}

subprojects
: setting.gradle 에 include 된 프로젝트를 전부 관리한다.
: rootproject 까지 적용시키고 싶은 경우 allprojects 로 등록하면 된다.

project
: 하위 프로젝트의 의존성 관리한다.
: velog-core 의 경우 공통 모듈이기 때문에 velog-api-server, velog-batch-server 에 의존성을 주입해준다.

위와 같이 설정을 해준다음 velog-api-server 가 velog-core 에 대한 의존성을 가지고 있는지 확인하려면 Gradle > Dependencies > compileClasspath 를 확인해주면 된다.

velog-api-server 와 velog-batch-server 에 velog-core 를 정상적으로 의존성을 가지고 있는 걸 확인할 수 있다 🙂

4. 모듈 설정

velog-api-server :: API 서버 모듈
api 서버 모듈 에 아래 파일을 생성해준다.

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

resources > application.yml

server:
  port: 8000

: 서버 포트번호를 8000 으로 설정해준다.
: 원하는 포트번호가 있는 경우 해당 포트 번호로 설정해주면 된다.

com.soyeon.velog > ApiApplication.java

package com.soyeon.velog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

: 패키지를 만들고 ApiApplication 파일을 만들어준다.
: @SpringBootApplication 어노테이션을 통해 웹 어플리케이션이 실행 될 수 있도록 한다.

Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package. 오류가 발생하는 경우
➡️ 패키지를 지정하지 않아 발생하는 오류로 패키지를 만들고 그 안에 Application 코드를 넣어주자.

velog-batch-server :: 배치 서버 모듈
build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}

resources > application.yml

server:
  port: 8001

: 포트 번호를 8081로 설정해준다.
: 원하는 포트 번호가 있다면 그걸로 지정해주되, velog-api-server 와는 다르게 지정해준다.

com.soyeon.velog > BatchApplication

package com.soyeon.velog;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BatchApplication {
    public static void main(String[] args) {
        SpringApplication.run(BatchApplication.class, args);
    }
}

: 패키지를 만들고 BatchApplication 파일을 만들어준다.
: @SpringBootApplication 어노테이션을 통해 웹 어플리케이션이 실행 될 수 있도록 한다.

서버 정상작동 확인
ApiApplication 혹은 BatchApplication 을 실행시켜준다.

velog-api-server url 👉 localhost:8000
velog-batch-server url 👉 localhost:8001

예제 그대로 따라했다면 위의 url로
혹은 포트를 수정했다면 수정한 포트로 접속하면 정상 작동을 확인 할 수 있다.

아직 만든 API 가 없기 때문에 각각의 url 로 접속했을 때 아래와 같은 화면이 뜬다면 서버가 정상적으로 실행된 것이다.

5. 공통 모듈 (velog-core) 의존성 테스트

velog-core 에 com.soyeon.velog.entity 라는 패키지를 만들고 가상으로 Member entity 를 만들어보자. 코드는 아래와 같다.

com.soyeon.velog.entity > Member.class

package com.soyoen.velog.entity;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Member {
    String name;
    int age;
}

: Member 는 이름과 나이를 가지고 있다고 가정한다.
: @Getter, @Setter, @ToString 은 롬복 어노테이션으로 get 메서드, set 메소드, toString 메서드를 자동 생성해준다.

velog-api-server 에 ApiController 를 만들어주고 Member 객체를 사용해보자.
velog-api-server 는 velog-core 에 의존성을 가지고 있기 때문에 Member 객체를 사용할 수 있다.

package com.soyeon.velog.controller;

import com.soyoen.velog.entity.Member;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApiController {

    @GetMapping("/test")
    public String test() {
        Member member = new Member();
        member.setAge(10);
        member.setName("이름");
        return member.toString();
    }
}


: import 된 값인 import com.soyoen.velog.entity.Member; 와 위의 사진을 보면 velog-core 에 있는 클래스를 import 해서 사용하고 있다는 걸 확인할 수 있다.


API 로 접속해봤을 때에도 정상적으로 결과가 나오는 걸 확인할 수 있다.

해당 멀티모듈은 공부를 할 때에도 유용하게 사용할 수 있다.
나의 경우에는 velog 예제 프로젝트를 관리할 때 멀티모듈을 사용하는데 하나의 큰 관심사에 여러 프로젝트를 한번에 관리할 수 있는 점이 좋다 👻

velog 예제 프로젝트 👉 https://github.com/soyeon207/velog_example

레퍼런스 🙇‍♀️

멀티모듈 설계 이야기 with Spring, Gradle
Gradle 멀티 프로젝트 관리
[스프링] 멀티 모듈(Multi Module) 개념/예제 feat. Gradle
[IntelliJ] 멀티 모듈 프로젝트 만들기
Gradle을 이용한 멀티 모듈

2개의 댓글

comment-user-thumbnail
2022년 4월 15일

멀티모듈에 대해서 공부하고 있었는데 많은 도움 되었습니다 :) 감사합니다 !

답글 달기
comment-user-thumbnail
2022년 9월 28일

velog-batch-server 포트 설정에 오타가 있습니다.
: 포트 번호를 8081로 설정해준다. -> : 포트 번호를 8001로 설정해준다.

답글 달기