멀티 모듈을 직접 세팅해본 경험은 없다보니 멀티 모듈 구성을 연습해보고 싶었다.
진행하면서 삽질을 많이 했다보니 경험을 기록한다.
실습
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
bootJar 는 executable archive
라고 하며 실행가능한 jar 이다.
어플리케이션 실행에 필요한 모든 의존성을 함께 빌드한다.
그래서 해당 jar 를 java -jar [jar 파일명]
으로 실행시키면 정상 작동한다.
하지만 Jar 는 plain 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: 멀티 모듈 환경 세팅하기
참고
- Gradle 멀티 프로젝트 관리
- Gradle을 이용한 멀티 모듈
- multi-modules-template/.gitignore at main · sangwoo0727/multi-modules-template · GitHub
- Gradle Could not find method compile() 해결 방법
- IntelliJ 멀티 모듈 프로젝트 만들기
- gradle 멀티모듈에서 spring 프로젝트 -> spring 프로젝트 의존성 연결하기
- Contact 1997 🚀
- dev-tips/IntelliJ-Gradle-멀티-모듈-프로젝트-Entity-모듈-분리.md at master · HomoEfficio/dev-tips · GitHub
- SpringBoot 2.5↑ 빌드 시 2가지 jar가 생성되는 현상 (executable jar & plain jar) — ROOPRETELCHAM
'Spring' 카테고리의 다른 글
스프링 컨트롤러 파라미터 한글 깨짐 현상 (0) | 2022.04.11 |
---|---|
스프링 3대 핵심 - ② PSA (Portable Service Abstraction) (0) | 2020.02.18 |
스프링 3대 핵심 - ① IoC (Inversion of Control) (0) | 2020.02.18 |
Spring-PetClinic 프로젝트 실습 1 (0) | 2019.05.14 |
스프링 AOP 개념 (2) | 2018.12.24 |
댓글