springboot - gradle을 이용한 멀티모듈 프로젝트 만들기

springboot gradle 멀티모듈 프로젝트 만들기

개발환경

windows10

intelliJ 커뮤니티 버전

jdk1.8

들어가기

intelliJ 에서 gradle 기반 springboot 멀티 모듈 프로젝트를 한번 만들어보자.

멀티모듈을 어떻게 디자인 해야하는지는 다루지 않고, gradle을 이용해서 어떻게 모듈을 생성하고 모듈간의 의존성을 셋팅을 하는가에 중점을 둔 글이다.

1. 인텔리J에서 gradle 프로젝트 생성

일단 intelliJ 에서 gradle 프로젝트를 생성하자.

http://start.spring.io 로 이동해서 spring boot gradle 프로젝트를 생성하자.

(나는 인텔리J 커뮤니티 버전을 사용중이라 springboot 프로젝트를 생성할 때 주로 http://start.spring.io 를 주로 사용한다.)

아래처럼 설정하여 프로젝트를 생성하자.

Project : Gradle Project

Language: Java

Spring Boot: 2.1.9(현재 2점대 이상으로 선택하면 될듯)

Project Metadata

Group : com.hanumoka.go

Artifact : go-modules

Option

Packaging: War

Java : 8

Dependencies: Spring web, Thymeleaf

위에서 중요한 부분은 Group이다.

com.hanumoka.go는 이 프로젝트의 공통 패키지이며, Artifact: go-modules 는 실제 생성되는 실행 프로그램을 구별하는 명칭이 아니라 모듈의 묶음일 뿐이다.

개인적으로 프로젝트를 war로 설정해서 생성한 이유는 애시당초 war로 프로젝트를 생성하면 프로젝트 빌드시 war, jar 빌드가 쉽기 때문이다.

Spring web은 필수이며 Thymeleaf 스프링 컨트롤러의 동작을 확인하기 위해 추가했다.

설정된 값을을 이용해서 압축된 프로젝트를 다운로드 하자.

해당 파일을 압축을 풀고 intelliJ로 open하자.

위처럼 gradle 이 제대로 빌드 되는지 확인하자.

컨트롤러와 html 페이지를 추가해서 스프링 컨트롤러 동작을 한번 시켜보자.

com.hanumoka.go.gomodules 패키지를 선택하고 controller 패키지를 생성하고, HomeController를 생성하고 html을 리다이렉팅 할 수 있는 RequestMapping 메소드를 추가하자.

GoModulesApplication 를 선택하고 run 시켜서, http://localhost:8080 로 접속해서 컨트롤러가 동작하는지 보자.

스프링 컨트롤러가 정상 동작하는 것을 확인 할 수 있다.

2. 모듈 추가하기

1번에서 한 일은 그냥 gradle 기반 springboot 프로젝트를 생성하고 동작시킨 것이다.

이제 실제 사용할 모듈을 구상하고 추가하고 셋팅해야 한다.

이 글은 gradle환경에서 springboot 프로젝트에서 모듈을 추가하고 연결하는 설정을 기록하는데 초점을 두고 있다.

따라서 간단하게 Service 모듈과 Controller 모듈을 생성하고 Controller 모듈이 Service 모듈을 사용하는 시나리오로 진행 하겠다.

실제 모듈을 설계하고 구성하는 일은 많은 고심이 필요해 보인다.(이부분은 나중에 좀 연구해 봐야 겠다.)

일단 프로젝트 루트 경로의 build.gradle, settigns.gradle 은 프로젝트 전체에 적용되는 설정 파일이다.

사실 gradle을 잘 몰라 자세한 설명을 할 수가 없다.

하지만 이후로 추가될 모듈에 관련된 공통적인 설정은 이 두 파일에 기술된다.

그리고 프로젝트 루트 경로의 src 폴더는 모듈을 추가함으로써 사라질 예정이다.

일단 a-module 이라는 이름의 모듈을 추가해보자.

일단 루트 경로의 settings.gradle을 확인해보자.

아래처럼 루트 프로젝트 네임만 있을 것이다. 나중에 모듈을 추가하면 모듈 정보가 추가될 것이다.

일단 넘어가자.

rootProject.name = 'go-modules'

그리고 루트 경로의 build.gradle 파일을 열어서 내용물을 모두 지우고 아래 내용으로 치환하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
buildscript {
ext {
springBootVersion = '2.1.9.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath "io.spring.gradle:dependency-management-plugin:1.0.8.RELEASE"
}
}

subprojects {

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'com.hanumoka.go'
version = '0.0.0'
sourceCompatibility = 1.8

repositories {
mavenCentral()
}


task initSourceFolders {
sourceSets*.java.srcDirs*.each {
if( !it.exists() ) {
it.mkdirs()
}
}

sourceSets*.resources.srcDirs*.each {
if( !it.exists() ) {
it.mkdirs()
}
}
}

dependencies {
compileOnly('org.projectlombok:lombok')
}
}

buildscript 부분에서 공통 스브링부트 버전등을 설정한다.

subprojects 는 추가될 모듈둘에 공통적으로 적용될 내용들이 기술되어 있다.

이제 a-module 을 추가해보자. 아래처럼 모듈을 클릭하자.

아래 내용을 확인하고 next 버튼을 클릭하자.

아래처럼 GroupId : com.hanumoka.go

ArtifactId : a-module 를 입력하고 next 를 클릭하자.

a-module 이라는 모듈명을 확인하고 Finish 버튼을 클릭하자.

아래처럼 a-module이 추가되었다. 하늘색 작은 상자가 표시 되어 있는데, 이것이 모듈을 의미한다.

모듈을 추가했으니 프로젝트 루트 경로의 settings.gradle 파일을 열어보자.

아래처럼 include 'a-module' 이라는 내용이 자동으로 추가된 것을 확인 할 수 있다.

만약 없다면, 추가해주자.

그리고 루트 경로의 settings.gradle 파일을 열어보자.

그리고 아래 내용을 추가해주자. 프로젝트해당 모듈이 있다고 등록하는 것이다. 나중에 이 모듈에 대한 디펜던시도 추가할 것이다.

project(':a-module') {
}

이제 생성했던 a-module 폴더로 들어가서 a-module 폴더의 build.gradle 파일을 열어보자.

기존의 내용들을 지우고 아래 내용으로 치환하자.

이 파일은 a-module을 위한 독자적인 파일이다.

dependencies {
    compile('org.springframework.boot:spring-boot-starter-thymeleaf')
    compile('org.springframework.boot:spring-boot-starter-web')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

그리고 아래처럼 모듈 내부의 패키지와 파일들을 구성하자.

공통 패키지는 com.hanumoka.go 이다.

BeanScan의 기준이 되는 AmoduleApp.class, ServletInitializer.class 는 이곳이 둬야 한다.

아래 AmoduleApp.class 파일이다.

package com.hanumoka.go;

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

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

아래 ServletInitializer.class 파일이다.

package com.hanumoka.go;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(AmoduleApp.class);
	}

}

아래 HomeController.class 이다.

추가한 a-module을 다른 모듈과 구분하기 위해 amodule 을 추가했다.

package com.hanumoka.go.amodule.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HomeController {

    @RequestMapping("/")
    public String index(){
        return "index";
    }
}

기존에 루트 경로에 있던 src 폴더 내부를 옮겨와서 AmoduleApp 파일명만 변경한 것이다.

그리고 루트 경로의 src 폴더를 제거하자.

지금까지 작업은 기존의 단일 프로젝트의 src를 a-module로 옮긴것이다.

AmoduleApp 을 실행 하면, 스프링 앱이 동작하고 http://localhost:8080 접근시 index.html 이 보여야 한다.

지금까지 한 작업으로 springboot 단일 프로젝트를 springboot 모듈 프로젝트로 변경 되었다.

이제 b-module을 추가하고 a-module에서 b-module을 사용하는 구조로 만들어보자.

b-module 이라는 모듈 추가하기

앞서 a-module 추가하듯이 b-module도 추가하자.

아래와 같은 구조가 될 것이고, src 폴더는 앞에서 말한것 처럼 제거 했다.

루트 경로에 settings.gradle 폴더르르 보면 역시 b-module 이 추가된 것을 볼 수 있다.

루트 경로의 build.gradle 에 가서 앞서 등록했던 a-module에 dependencies 를 방금 추가한 b-module 로 추가하자.

해당 내용은 a-modul이 b-module에 의존성을 갖는다는 것이다.

project(':a-module') {
    dependencies {
        compile project(':b-module')
    }
}

b-module을 열고 아래처럼 구성하자.

b-module은 a-module에서 사용할 서비스로 Bservice.class를 제공한다.

Bservice.class

package com.hanumoka.go.bmodule.service;

import org.springframework.stereotype.Service;

@Service
public class Bservice {
    public String test(){
        return "Bservice test()...";
    }
}

그리고 b-module 하위이 build.gradle 을 아래로 치환 했다.

bootJar{
    enabled = false;
}
jar {
    enabled = true;
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter')
}

A-module 컨트롤러에서 B-module 서비스를 사용해보자.

A-module의 HomeController.class를 아래처럼 수정하자.

package com.hanumoka.go.amodule.controller;

import com.hanumoka.go.bmodule.service.Bservice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HomeController {

    @Autowired
    Bservice bservice;

    @RequestMapping("/")
    public String index(){

        System.out.println(bservice.test());
        return "index";
    }
}

이제 a-module의 AmoduleApp을 실행해서 a-module의 컨트롤러가 동작할때 b-module의 서비스를 호출하는지 확인해보자.

아래처럼 동작을 확인 할 수 있다.

go-module 을 빌드하면 아래처럼 a-module 의 빌드 결과물을 확인 할 수 있다.

화면에는 안 보이지만 b-module 역시 빌드 결과물이 생겼다.

하지만 a-module에만 SpringBootApplication을 등록했으므로, 실제 실행 시킬수 있는 jar 파일은

a-module-0.0.0.jar 이다.

직접 jar를 실행시켜, 정상동작을 확인하자.

java -jar a-module-0.0.0.jar 

마무리

이 글에서는 간단하게 gradle 기반으로 spring boot 멀티 모듈을 구축하는 방법을 정리하였다.

사실 실제 멀티 모듈을 설계하고 구축하는 일은 어려운 일이고, 많은 고민이 필요해 보인다.

하지만 나처럼 gradle 자체를 잘 모르는 사람은 실제 구축 자체가 어려운 일이므로 이렇게 기록해 놓는다.

해당 예제는 아래 github에 올려놓았다.

https://github.com/hanumoka/springboot_gradle_multimodule

참고자료

https://bkjeon1614.tistory.com/38