본문 바로가기
Spring

멀티 모듈 세팅하기

by 성건희 2022. 8. 2.
반응형

멀티 모듈을 직접 세팅해본 경험은 없다보니 멀티 모듈 구성을 연습해보고 싶었다.
진행하면서 삽질을 많이 했다보니 경험을 기록한다.

실습

IntelliJ 로 Spring Initializr 프로젝트를 만들어준다.
프로젝트 명은 multi-module-demo 로, dependency 는 web, lombok 을 추가했다.

실습할 모듈은 아래와 같이 2개를 만들것이다.


  • app-api : API 모듈
  • app-common : 공통 모듈

기본적으로 multi-module-demo 프로젝트에 만들어지는 src 폴더는 사용하지 않을 예정이므로 제거한다.

app-common 모듈 추가하기

그 후 아래와 같이 Module 을 추가해준다.

모듈의 이름은 app-common 으로 설정하고 dependency 는 'jpa, h2, mysql' 을 추가해준다.
그러면 기본적으로 .gitIgnore, gradlew 등등 여러 파일이 같이 생길텐데
빌드는 항상 root 프로젝트를 기준으로 진행할 예정이므로, 아래와 같이 src, build.gradle 만 남기고 전부 제거한다.


그 후 app-common 의 build.gradle 을 아래와 같이 바꿔준다.

dependencies {
    compileOnly 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    compileOnly 'mysql:mysql-connector-java'
}

bootJar { enabled = false }

jar { enabled = true }

스프링 부트 2.0 이상이라면 위와 같이 bootJar { enabled = false } jar { enabled = true } 로 추가해주면 된다.

참고 ) bootJar VS Jar

bootJarexecutable archive 라고 하며 실행가능한 jar 이다.
어플리케이션 실행에 필요한 모든 의존성을 함께 빌드한다.
그래서 해당 jar 를 java -jar [jar 파일명] 으로 실행시키면 정상 작동한다.


하지만 Jarplain archive라고 하며, 어플리케이션 실행에 필요한 모든 의존성을 포함하지 않고,
소스코드의 클래스 파일과 리소스 파일만 포함한다.


SpringBoot 2.5.0 이상 버전을 사용한다면, Gradle 을 통한 빌드 시, BootJar 와 Jar task 가 모두 실행되어
build/libs 위치에 jar 가 2개 생겨 에러가 발생한다.
app-common 은 독립적으로 실행 될 필요가 없으므로 bootJar { enabled = false } 속성을 추가해 준다.

root build.gradle 설정하기

root 인 multi-module-demo 의 build.gradle 을 아래와 같이 설정한다.

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

subprojects {
    group = 'com.geon'
    version = '0.0.1-SNAPSHOT'

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

    sourceCompatibility = '11'

    repositories {
        mavenCentral()
    }

    configurations {
        compileOnly {
            extendsFrom annotationProcessor
        }
    }

    dependencies {
        compileOnly 'org.projectlombok:lombok'
        annotationProcessor 'org.projectlombok:lombok'
        testImplementation 'org.springframework.boot:spring-boot-starter-test'
    }
}

subprojects 는 settings.gradle 에 include 된 프로젝트 전부를 관리한다.
root 프로젝트까지 적용하고 싶다면 allprojects 로 등록하면 된다.


그 후 settings.gradle 에 아래와 같이 추가해주면 된다.

rootProject.name = 'multi-module-demo'

include 'app-common'

위 코드는 root 인 multi-module-demo 프로젝트가 app-common 프로젝트를 하위 프로젝트로 관리하겠다는 의미이다.

model 추가하기

app-common 에 공통 member 엔티티를 아래와 같이 추가하자.

@Getter
@NoArgsConstructor
@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_id")
    private Long id;

    private String name;

    public Member(String name) {
        this.name = name;
    }
}

그 후 MemberRepository 를 아래와 같이 만들었다.

public interface MemberRepository extends JpaRepository<Member, Long> {
}

app-api 모듈 추가하기

이제 위에서 했던 것 처럼 모듈을 추가해서 app-api 를 만들어보자.

dependency 는 'web, jpa, h2, mysql' 을 추가했다.
그 후 app-api 의 build.gradle 을 아래와 같이 추가한다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    runtimeOnly 'com.h2database:h2'
    runtimeOnly 'mysql:mysql-connector-java'
}

app-api 에서 app-common 의 repository 를 사용할 예정이므로
root 의 build.gradle 하단에 아래 내용을 추가한다.

...

project(':app-api') {
    dependencies {
        compileOnly project(':app-common')
    }
}

참고로 compile 은 gradle 6 부터 deprecated 되었으므로, compileOnly 를 사용하였다.
그리고 : 는 디렉토리 path 를 의미한다.

그 후 root 의 settings.gradle 에 app-api 를 하위 프로젝트로 추가해준다.

rootProject.name = 'multi-module-demo'

include 'app-api', 'app-common'

그리고 app-api 의 application.yml 을 세팅해준다.

spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/springbook
    username: sa
    password:
    driver-class-name: org.h2.Driver
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: create

참고로 프로젝트를 실행할 때는 H2 를 다운받고 H2 서버를 띄운 후 실행해야한다.
(설치법은 구글링하면 나오니 생략한다.)

MemberService 추가하기

이제 셋팅은 끝났으므로 app-api 에 MemberService 를 추가해보자.

@Service
public class MemberService {

    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}

여기서 MemberRepository 는 app-common 모듈의 것을 사용한다.
그 후 app-api 를 실행하면 MemberRepository bean 을 찾지 못한다는 에러가 발생하는데..여기서 삽질을 많이했다.
해결은 아래와 같이 AppApiApplication 에서 app-common 을 스캔 범위에 추가해야한다.

@EntityScan(basePackages = {"com.geon.appcommon"})
@EnableJpaRepositories(basePackages = {"com.geon.appcommon"})
@SpringBootApplication
public class AppApiApplication {

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

}

그리고 app-api 를 실행하면 정상적으로 실행된다.

소스코드

GitHub - gbeea1004/multi-module-demo: 멀티 모듈 환경 세팅하기

참고

반응형

댓글