ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1. 그레이들 멀티프로젝트 - 셋업하기
    스프링개발자/301 - 아키텍처 2020. 8. 30. 02:11

    [배경]

    반복되는 코드 줄이기 쉽다.

    여러 어플리케이션을 하나의 git repo에서 관리하기 쉽다.

     

    참고: https://docs.gradle.org/current/userguide/multi_project_builds.html


    1. Intellij IDEA 프로젝트 생성

    Spring Initializr를 쓴다. 특별한 것은 없고 대략의 설정은 다음과 같다;

     

    group: com.example

    Type: Gradle Config (Generate a Gradle build file.)

    Artifact: monorepo

    Packaging: Jar

    프로젝트를 처음 설정하면 나오는 다음의 tip들을 yes 한다;

    configure automatically

    auto import

     

    다음의 오류가 떴다. 나의 현재 gradle 버전이 오래되서 plugin을 못쓴다는 말인데

     

    나의 gradle버전을 확인해보니 정말 5.2.1. 플러그인을 쓰기 위해 최신으로 업데이트 해준다.

    gradle wrapper를 다운받아서 root 디텍토리에 넣으면 된다. 6.4.1 폴더가 생겼다.

    짜잔, 회색으로 나왔던 키워드들이 흰색으로 변함(인식함)

    첫 키워드 plugins를 ctrl+click 해보면

    새로 받은 gradle 6.4.1에서 인식

     

    2. Multi-Module 만들기

     

    Gradle project with Java

    다음의 이름들로 모듈 2개 생성: main-application, weather-application

     

    main 메소드가 들어가 있는 어플리케이션 클래스를 만든다.

    package com.example.monorepo;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            SpringApplication.run(MainApplication.class, args);
        }
    }
    

     

    import를 하였음에도, 아래 그림의 9번째 줄에 컴파일 에러가 생긴다. 

    gradle refresh를 누르면 3번,4번줄에 있는 import 또한 회색으로 변하면서 인식하지 못한다.

    이것은 root폴더에 있는 build.gradle이 main-application에 적용되지 못해서 생기는 문제다.

    main-application폴더에 build.gradle이 root폴더의 것을 덮어쓰고 있기 때문이다.

    3. Gradle subprojects

    subproject가 이 글의 핵심키워드이다.

     

    root 폴더에 있는 build.gradle이 모든 subproject들에 적용되도록 gradle subprojects 를 추가한다.

    그 안에 dependency 정보를 넣어준다. 앞으로 생성되는 subproject들에 공통적으로 여기의 의존성이 자동적용된다.

     

    subprojects {
    
        group 'com.example.monorepo'
    
        apply plugin: 'java'
        apply plugin: 'eclipse'
        apply plugin: 'org.springframework.boot'
        apply plugin: 'io.spring.dependency-management'
        apply plugin: "jacoco"
    
        repositories {
            jcenter()
            mavenCentral()
            mavenLocal()
            maven {
                url "https://oss.sonatype.org/content/repositories/snapshots"
            }
            maven {
                url 'http://repo.hortonworks.com/content/repositories/releases/'
            }
            maven {
                url "https://repo.spring.io/plugins-release/"
            }
            maven {
                url "https://repo.spring.io/libs-release/"
            }
        }
    
        dependencyManagement {
            imports {
                mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
                mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}"
            }
        }
    
        dependencies {
            implementation 'org.springframework.boot:spring-boot-starter-actuator'
            implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
            implementation 'org.springframework.boot:spring-boot-starter-web'
            implementation 'org.springframework.cloud:spring-cloud-config-server'
            implementation 'org.springframework.cloud:spring-cloud-starter-config'
            implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'
            compileOnly 'org.projectlombok:lombok'
            runtimeOnly 'com.h2database:h2'
            annotationProcessor 'org.projectlombok:lombok'
            testImplementation('org.springframework.boot:spring-boot-starter-test') {
                exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
            }
        }
    
    
    }

    이후에 gradle re-import를 하면, 메인클래스 9번째 줄의 빨간줄이 없어진것을 볼 수 있다.

     

    마지막으로, main-application에 포트넘버와 이름을 설정한다

    server.port=8080
    spring.application.name=main-application

    weather-application또한 다음과 같이 설정한다

    server.port=8081
    spring.application.name=weather-application

    4. 눈으로 확인해보자

    MainApplication을 실행한다

    o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 8080

    WeatherApplication또한 실행한다 8081포트에서 실행되었다.

    하나의 repository에 있기 때문에 의존성 및 자원관리도 쉽고 효율적이다. 

     

    5. Gitrepo initial commit

    다음의 이름으로 repo를 생성하였다. https://github.com/2ndPrince/monorepo

     

    Intellij Terminal에서 코드를 push하자

    예전 글(https://2ndprince.tistory.com/11?category=880036)에서 발췌

    이렇게 해서 하나의 git repository 안에 multiple application이 잘 동작하는 프로젝트 완성!

    의존성을 쉽게 관리 할 수 있음

     

    모든 소스코드

    https://github.com/2ndPrince/monorepo/tree/monorepo_first


    [TroubleShooting]

    1. 어플리케이션이 잘 작동되고 있는데, run텝에 error trace들이 생긴다.

    2020-08-29 13:04:28.579 ERROR 16496 --- [           main] c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://localhost:8761/eureka/}
    
    com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: connect
    ...
    com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

    eureka서버를 찾지 못해서 나오는 에러인데, 당장 어플리케이션 구동에는 문제가 없다.

    root build.gradle에서 다음의 implementation을 지우고, 어플리케이션을 다시 동작하면 문제가 사라진다.

    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server'

    하지만, 곧 eureka application을 만들거라서 의존성을 냅두자. autoconfigure로 가져온 bean 중에 euraka server와 client를 밝혀줘야 되는게 있는데, 우리가 정보를 주지 않아서 그렇다.

Designed by Tistory.