-
Multi Module정리/유용 기능 2022. 11. 13. 20:11
- 레고를 조립하듯 필요한 Module을 조립할 수 있다.
- N개의 Module이 조립되어 있는 프로젝트를 Multi Module 프로젝트라고 부른다.
- Multi Module 프로젝트 구조를 사용하는 이유
- A 서버와 B 서버에서 동일한 DB Entity가 필요할 경우 중복된 Entity를 Module화 시켜 사용하기 위해 Multi Module 프로젝트를 사용한다.
* 만일 각 서버마다 Entity를 생성해서 관리한다면, 변경 사항 발생 시 각 서버마다 해당 Entity를 수정해야 하기 때문에 리스크가 늘어난다. - Multi Module 구조에서 원하는 Module만 골라서 빌드&배포가 가능하다.
- A 서버와 B 서버에서 동일한 DB Entity가 필요할 경우 중복된 Entity를 Module화 시켜 사용하기 위해 Multi Module 프로젝트를 사용한다.
실습
1. Root Project를 생성한다.
- Root Project를 생성하고 필요 없는 폴더와 파일을 삭제한다.
- src 폴더와 help.md 파일을 삭제하였다.
2. API Module을 생성한다.
- Root Project 우클릭 -> New -> Module을 선택한다.
- Module 정보를 입력하고 Module을 생성한다.
- api-module이 multi-module-study 안에 생성된 것을 확인할 수 있다.
* common-module도 api-module과 마찬가지로 생성한 후, Server 용 Module이 아니므로 Application.java 파일을 삭제한다
3. Root Project - settings.gradle 수정
- Root Project에 생성한 Module의 정보를 include 한다.
4. api-module과 common-module 의존성 설정
- api-module이 common-module을 참조하기 때문에 api-module의 build.gradle에 implementation project('common-module')을 추가한다.
- 이때, implementation project에 기입할 project 명은 Root Project의 settings.gradle에 작성한 Module이름과 같아야 한다.
- Root Project의 settings.gradle에서 Module을 관리하기 때문에 api-module의 settings.gradle을 제거한다.
- api-module, common-module build.gradle에 tasks.register(prepareKotlinBuildScripteModel) {} 코드를 추가한다.
5. common-module에 Java 파일 생성 후 확인
@Getter @AllArgsConstructor public enum ErrorCode { SUCCESS("200", "SUCCESS"), UNKOWN_ERROR("-9999", "UNKOWN_ERROR"); private String code; private String message; }
- common-module에 공통적으로 사용할 ErrorCode Enum을 생성한다.
@Service public class TestService { public String testSuccess() { return ErrorCode.SUCCESS.toString(); } } @RestController @RequiredArgsConstructor public class TestController { private final TestService testService; @GetMapping("/test") public String testSuccess() { return testService.testSuccess(); } }
- apu-module에 TestController와 TestService를 생성한다.
- Server를 실행하고 curl localhost:8080/test를 입력하면 common-module에서 생성한 ErrorCode.SUCCESS 값이 반환되는 것을 확인할 수 있다.
- Module을 참조하면 해당 Module의 Java 파일을 사용할 수 있다.
6. common-module에 Bean 생성 후 확인
@Service public class CommonService { public String commonSuccessResponse() { return ErrorCode.SUCCESS.toString(); } }
- common-module에 CommonService Bean을 생성한다.
@RestController @RequiredArgsConstructor public class TestController { private final TestService testService; private final CommonService commonService; @GetMapping("/test") public String testSuccess() { return testService.testSuccess(); } @GetMapping("/common/test") public String testCommonSuccessResponse() { return commonService.commonSuccessResponse(); } }
- api-module의 TestController에 testCommonSuccessResponse 함수를 생성한다.
- Server 실행 시, Parameter 1 of constructor in backstudy.apimodule.controller.TestController required a bean of type 'backstudy.commonmodule.service.CommonService' that could not be found. 다음과 같은 에러가 발생하는 것을 확인할 수 있다.
* Component Scan은 @SpringBootApplication이 존재하는 Class의 패키지 하위 내에서 이루어지기 때문에 해당 오류가 발생한다.
** 해결 방법1: ApiModuleApplication Class를 apimodule 패키지 상위로 이동시킨다.
ApiModuleApplication의 패키지 경로: backstudy.apimodule
common-module 내의 파일 경로: backstudy.~~
다음 상황에서 ApiModuleApplication을 상위 패키지로 옮기게 되면 backstudy에 위치하게 되어 common-module 내 파일을 Scan 할 수 있게 된다.
** 해결 방법2: @SpringBootApplication의 Component Scan 범위를 지정한다.
@SpringBootApplication( scanBasePackages = {"backstudy.apimodule", "backstudy.commonmodule"} )
7. 공통 Dependency 관리plugins { id 'java-library' } api 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2'
- common-module의 build.gradle에 추가한다.
@Getter @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; public Member(String name) { this.name = name; } } public interface MemberRepository extends JpaRepository<Member, Long> { }
- common-module에 Member Entity, MemberRepository를 생성한다.
@RestController @RequiredArgsConstructor public class MemberController { private final MemberRepository memberRepository; @PostMapping("/save-member") public Member saveMember() { Member member = new Member("test1"); return memberRepository.save(member); } }
- api-module에 MebmerController를 생성한다.
- Server를 실행하면 Entity와 Repository를 Bean 주입받지 못해 발생하는 에러가 발생한다.
@EntityScan({"backstudy.commonmodule.entity"}) @EnableJpaRepositories(basePackages = {"backstudy.commonmodule.entity"}) public class ApiModuleApplication { public static void main(String[] args) { SpringApplication.run(ApiModuleApplication.class, args); } }
- ApiModuleApplication에 위와 같이 Annotation을 붙여주면, 해당 경로에 존재하는 Entity와 Repostiory를 주입받아 Server가 정상적으로 실행된다.
- localhost:8080/save-member를 호출하면 정상적으로 생성된 member를 응답받을 수 있다.
Project Build
tasks.bootJar { enabled = false } tasks.jar { enabled = true }
- common-module의 build.gradle에 추가한다.
- bootJar를 true 설정하면 . jar 파일을 생성하는데 common-module의 경우 . jar 파일을 생성할 필요가 없어 false로 설정한다.
- bootJar가 true로 설정된 경우, Main 메서드를 찾아가는데 common-module의 경우 main 메서드를 제거했기 때문에 오류가 발생한다.
- jar = true 로 설정하면 xxx-plain.jar 파일을 생성하는데, 생성된 파일의 경우 Dependency를 가지지 않고 Class와 Resource만 포함하고 있기 때문에 Server를 실행시킬 수 없다.
* ./gradlew clean :api-module:buildNeeded --stacktrace --info --refresh-dependencies -x test 명령어로 프로젝트를 build 할 수 있다.
* jar 파일 실행 시, profile 설정은 -Dspring.profiles.active=[profile name] 명령어로 가능하다.
'정리 > 유용 기능' 카테고리의 다른 글
[소프트웨어 분석] Sonarqube (1) 2022.11.20 Android Studio 없이 Emulator 실행하기 (0) 2022.10.20 유용한 도구 모음 (1) (0) 2022.10.06 [IntelliJ] 클래스 생성 시 자동 주석 설정 (0) 2022.09.06