Chris Devlog

[Spring Boot] Multi Module Project feat. jdk17, Gradle 7.5.1 본문

Spring Boot

[Spring Boot] Multi Module Project feat. jdk17, Gradle 7.5.1

Chris Dev Heo 2022. 11. 30. 05:31
반응형

Gradle 6.X -> 7.X로 버전이 올라오면서 변경된 사항에 따라 설정이 조금 달라진 부분이 있어 글을 작성함.

jdk support gradle version

 


프로젝트 생성 및 버전

https://start.spring.io/

Gradle 6.X -> 7.X  configuration 변경사항

configuration 변경사항

기존 사용 중이던 compile 가 deplecate 되어 상황에 따라 api와 implementation를 선택하여 사용

 

implementation

  •  현재 모듈에서 사용

api 

  • java-library 플러그인을 추가필요
  • 상위 모듈에 적용 시 하위 모듈에서도 사용 가능 

자세한 내용은 https://docs.gradle.org/7.3/userguide/upgrading_version_6.html에서 확인


기존 Gradle 버전 변경 방법

intellij 사용 시 Terminal Local 경로에서 gradlew 확인(ls)

버전 변경

# ./gradlew wrapper --gradle-version={변경할 버전}
# 버전 업/다운 모두 가능
./gradlew wrapper --gradle-version=7.3

# 변경된 버전 확인
./gradlew -v

모듈 생성

main project -> New -> Module... -> New Module

New Module로 생성 시 src/main/java 하위 패키지는 생성되지 않음

하위 패키지는 두 모듈이 동일한 경로로 지정해야 오류가 발생하지 않기 때문에 build.gradle -> group(com.example)으로 패키지 생성

Main Project(demo)

build.gradle

plugins {
	id 'java'
	id 'org.springframework.boot' version '2.7.6'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
}

repositories {
	mavenCentral()
}

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

test {
	useJUnitPlatform()
}

module-core

  • plugins -> java-library(api 사용 시), boot, dependency-management(bootJar 사용시)
  • jpa, mysql 추가

build.gradle 

plugins {
    id 'java'
    id 'java-library' // api 사용시 추가
    id 'org.springframework.boot' version '2.7.6' // main project(demo) build.gradle 과 동일
    id 'io.spring.dependency-management' version '1.0.15.RELEASE' // main project(demo) build.gradle 과 동일
}

group 'com.example'
version '0.0.1-SNAPSHOT'

repositories {
    mavenCentral()
}

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

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

    api 'org.springframework.boot:spring-boot-starter-data-jpa' // java-library 추가시 api 사용가능
    implementation 'mysql:mysql-connector-java'
}

test {
    useJUnitPlatform()
}

application.yml

spring:
  main:
    allow-bean-definition-overriding: true
# url, username, password만 잘설정해주면됩니다
  datasource:
    url: jdbc:mysql://localhost:3306/dev
    username: dev
    password: developmnet
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    hibernate:
      ddl-auto: update # test용으로 update 사용
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        use_sql_comments: true
        jdbc:
          time_zone: Asia/Seoul # @CreatedDate 필드의 Time Zone 값 설정

Entity

package com.example.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Entity
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class Member {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column
  private String email;

}

Repository

package com.example.domain.repository;

import com.example.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {

}

module-api

  • 생성된 패키지 아래  ApiApplication 추가

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.6' // main project(demo) build.gradle 과 동일
    id 'io.spring.dependency-management' version '1.0.15.RELEASE' // main project(demo) build.gradle 과 동일
}

group 'com.example'
version '0.0.1-SNAPSHOT'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

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

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

    implementation project(':module-core')
}

test {
    useJUnitPlatform()
}

Service

package com.example.domain.member.service;

import com.example.domain.Member;
import com.example.domain.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MemberService {

  private final MemberRepository memberRepository;

  public Member saveMember() {
    return memberRepository.save(Member.builder()
        .email("chris@tistory.com")
        .build());
  }
}

settings.gradle 확인

module을 정상적으로 추가 시 settings.gradle에 includ 됨

 gradle reload All 버튼 클릭 시 모듈 확인 가능

main Project(demo) src 디렉터리 제거


테스트

package com.example.domain.member.service;

import static org.assertj.core.api.Assertions.assertThat;

import com.example.domain.Member;
import com.example.domain.repository.MemberRepository;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MemberServiceTest {

  @Autowired
  MemberService memberService;

  @Autowired
  MemberRepository memberRepository;

  @Test
  void test() {
    Member member = memberService.saveMember();
    Optional<Member> memberOptional = memberRepository.findById(member.getId());

    assertThat(memberOptional.isPresent()).isTrue();
    assertThat(memberOptional.get().getEmail()).isEqualTo(member.getEmail());
  }
}

결과

 

오류

    • Gradle reload시 오류(재현이 안돼서 스크린샷이 없네요..)
      • main project(demo) 하위가 아닌 같은 레벨에 모듈이 생성되었는지 확인
    • Could not find method bootJar() for arguments
      • 해당 모듈 Gradle에 plugin 추가하지 않고 bootJar 추가한 경우
    • required a bean of type '*Repository' that could not be found.
      • src/main/java 하위 패키지 구조가 모듈 간 일치하지 않는 경우

 

참조

https://docs.gradle.org/current/userguide/compatibility.html

https://docs.gradle.org/7.3/userguide/upgrading_version_6.html

https://jojoldu.tistory.com/538

 

반응형