멀티 프로젝트로 build를 하면 javadoc 파일은 프로젝트별로 생성 되어 집니다. 이를 하나의 javadoc으로 합치고자 할 때 기능이 제공 되지 않아 정말 아쉬움이 생깁니다. 그리고 lombok 사용시 get, set, toString.. 같은 method는 javadoc에서 나오지 않 나오기 때문에 이것도 javadoc에서 표현 하고 싶은 아쉬움도 생깁니다. 이 문제를 해결 하기 위해서 lombok라이브러리에서 제공되고 있는 Ant를 이용한 제네레이터 작업을 delombok이라 하며 이것을 gradle에서도 ant 문법을 이용해 손쉽게 적용 할 수 있습니다. delombok을 처리 하기 위해 이제 별도의 delombok.gradle 파일을 하나 만들고 다음 처럼 작업 합니다.

// 통합 javadoc 파일 만들기 task
task alljavadoc(type: Javadoc) {
    options {
        encoding = 'UTF-8'
        memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
        author = true
        header = project.name
        addStringOption('Xdoclint:none')
    }
    // 서브 프로젝트 빌드 폴더에 delombok 처리 되어 있는 자바 파일을 대상 소스로 간주함.
    source subprojects.collect { project ->
        "${project.getBuildDir()}/src-delomboked"
    }
    // alljavadoc 파일이 만들어 질 폴더 지정
    destinationDir = new File(buildDir, 'allJavadoc')
    // java source의 classpath 지정
    classpath = files(subprojects.collect { project ->
        project.sourceSets.main.compileClasspath
    })
}

configure(subprojects.findAll { subproject -> subproject.plugins.hasPlugin('java') }) {

    // lombok 적용 파일을 delombok 처리
    task delombok {
        ext.srcDelomboked = "${buildDir}/src-delomboked"
        def srcJava = 'src/main/java'

        // gradle compileJava task를 dependency
        dependsOn configurations.compile.getTaskDependencyFromProjectDependency(true, 'compileJava')

        // delombok 처리 할 파일과 위치 지정
        inputs.files file(srcJava)
        outputs.dir file(srcDelomboked)

        doLast {
            def collection = configurations.compile
            def sumTree = collection + fileTree(dir: 'bin')

            // lombok에서 제공 하고 있는 ant를 이용한 delombok 처리 방법을 gradle에서 이용
            ant.taskdef(name: 'delombok', classname: 'lombok.delombok.ant.DelombokTask', classpath: configurations.compile.asPath)
            ant.delombok(from: srcJava, to: srcDelomboked, classpath: sumTree.asPath)

            copy {
                from {
                    srcDelomboked
                    fileMode 0744
                }
                into srcJava
            }
        }
    }

    // javadoc은 delombok 처리 되어 있는 파일을 소스로 간주 함.
    javadoc {
        dependsOn delombok
        source = fileTree(dir: delombok.srcDelomboked)
        options {
            encoding = 'UTF-8'
            memberLevel = org.gradle.external.javadoc.JavadocMemberLevel.PROTECTED
            author = true
            header = project.name
            addStringOption('Xdoclint:none')
        }
    }

}

그리고 build.gradle에 다음처럼 delombok.gradle 파일을 적용 합니다.

// 1. buildScript 선언
// Gradle에서 제공 되는 빌드 기능 이외의 직접 만든 Plugin 기능이나 외부 기능(외부 라이브러리)을 사용하고자 한다면 추가로 정의
buildscript {
    .. 생략
    dependencies {
        classpath 'io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE'
    }
}

// 자바 기본 설정
apply from: "${gradleScriptDir}/default.gradle"

project('foundation:sample-boot-config') {
    dependencies {
        // Spring Boot
        compile 'org.springframework.boot:spring-boot-starter'
        // Lombok
        compile 'org.projectlombok:lombok:$lombokVersion'
    }
}

project('foundation:sample-boot-web-config') {
.... 이하 생략

// 위에서 만든 delombok.gradle 파일을 맨 하단에 적용 합니다.
apply from: "${gradleScriptDir}/delombok.gradle"

그리고 다음 처럼 실행 하고 난 후...




루트 프로젝트 build 폴더를 확인 하면 alljavadoc 이라는 폴더가 만들어 집니다.



그리고 해당 폴더를 들어가 보면 모든 프로젝트의 javadoc파일이 하나의 singlejavadoc으로 만들어 진 것을 볼 수 있습니다.



이제 다음 섹션 에서는 jar, war 와 같은 아카이브를 어떻게 만들어야 하고 사내 리포지토리(nexus, artifactory) 에 어떻게 upload 해야 하는지 그리고 멀티프로젝트에서 resources 파일들을 어떻게 공통으로 사용 할 수 있는지에 대해 이야기 하겠습니다.


Sample Source Github Link

https://github.com/gmind7/gradle-with-springboot

Posted by G마인드

댓글을 달아 주세요


gradle에서 profiles라는 command arguments를 통해 환경 별로 사용하는 다이나믹 변수 선언 방법에 대해 얘기 하려고 합니다.

우선 환경별 설정 파일인 environment.groovy 이라는 파일을 생성 후 변수 선언을 합니다.

environments {
    local {
        artifactory {
            host.url = 'http://localhost/artifactory'
            username = 'sample'
            password = 'sample'
        }
    }
    dev {
        artifactory {
            host.url = 'http://dev/artifactory'
            username = 'sample'
            password = 'sample'
        }
    }
    rc {
        artifactory {
            host.url = 'http://rc/artifactory'
            username = 'sample'
            password = 'sample'
        }
    }
    live {
        artifactory {
            host.url = 'http://live/artifactory'
            username = 'sample'
            password = 'sample'
        }
    }
}

buiid.gradle 파일에서 다음과 같이 환경 변수에 맞게 사용 할 수 있도록 설정 합니다.

buildscript {
    ext.gradleScriptDir = "${project.getRootDir()}/gradle"

    def profile = project.hasProperty('profile') ? project.getProperty('profile') : 'local'

    logger.quiet "######### Lodding Configuration For Profile Active : [${profile}] ###########"

    def configFile = file("${gradleScriptDir}/environment.groovy")
    def parsedConfig = new ConfigSlurper(profile).parse(configFile.toURI().toURL())

    ext.env = parsedConfig

    logger.quiet "######### Artifactory Host URL : [${env.artifactory.host.url}] ###########"
}


그럼 이제 적용이 잘 되었는지 확인 해 보도록 하겠습니다.



환경 변수를 적용 하지 않고 실행시 default local 이라는 환경 변수 값 사용이 되며

아래 처럼 -Pprofile=dev 라고 argument를 던지면 해당 profile에 맞게 값이 변동 되어 집니다.



ext.env = parsedConfig 로 선언 된 후 gradle의 모든 파일에서 env.*** 형태로 접근 하면 환경 변수에 맞는 값을 돌려 줍니다.

그리고 기본 프로퍼티 값을 사용 하기 위해서는 루트 폴더 밑에 바로 gradle.properties 라는 파일을 만들고 아래 처럼 고정 된 값을 선언 합니다.

// Sample Project
sampleCurrentVersion = 0.0.1
// 의존성 라이브러리 버전 정보
//.... 생략

그리고 아래처럼 gradle 파일에서 ${변수명} 형태로 바로 사용 합니다. gradle.properties 파일은 자동으로 import 처리 되어 집니다.

buildscript {
..... 생략
    logger.quiet "######### Lodding Configuration For Profile Active : [${profile}] Version : [${sampleCurrentVersion}] ###########"
..... 생략
}


이처럼 gradle 에서는 properties 파일과 groovy 파일을 혼용 하여 여러 환경에 맞는 값들을 다이나믹하게 이용 할 수 있어 프로젝트 성격에 맞게 적용 할 수 있습니다.

다음 섹션에서는 이어서 각 프로젝트들의 jar, war 파일을 만들 때는 또 어떻게 커스텀 하게 처리 해야 되고 upload시에도 어떻게 관리 해야 되는지 이어 가겠습니다.


Sample Source Github Link

https://github.com/gmind7/gradle-with-springboot

Posted by G마인드

댓글을 달아 주세요




Gradle를 사용하다 보면 몇 가지 중요한 설정이 있는데 그 중에서 설정 중복 처리 방법과 의존성 라이브러리 버전 충돌 문제와 일반적인 라이브러리의 버전 업에 따른 설정과 Maven SNAPSHOT 같은 파일만 변하는 라이브러리 관리를 위해 몇 가지 설정이 필요 합니다. 이런 설정을 관리 하기 위해서는 Gradle들에서 configurations 라는 기능과  te,allprojects, subprojects 기능으로 아주 쉽게 설정을 할 수 있습니다.

그럼 이제 의존성설정관리를 위해서 기능별로 파일을 분리 할 차례입니다. build.gradle에서 별도의 다른 gradle(default.gradle)파일을 적용하기 위해서는 apply from: 'default.gradle' 기능으로 적용 할 수 있습니다. 

buildscript {
   // ext 변수는 gradle에서 기본으로 제공 되고 있는 변수 이며 ext.xxx 형태로 선언 했던 값 들은 gradle 파일에서 전역 변수 형태로 사용 가능 합니다.
    ext.gradleScriptDir = "${project.getRootDir()}/gradle"
    .... 이하 생략
}
// 다른 gradle 파일 적용 하기
apply from: "${gradleScriptDir}/default.gradle"

그리고 default.gradle 파일을 다시 보면 다음과 같습니다.

 

allprojects {
   // 전체 프로젝트에 공통 적으로 설정 할 스크립트 처리
    .....
}
configure(allprojects.findAll { allprojects -> allprojects.name.contains('-') }) {
  // 자바 프로젝트 관련 설정 처리
}

이제는 먼저 자바 설정을 제대로 한번 해 줍니다.


configure(allprojects.findAll { allprojects -> allprojects.name.contains('-') }) {
    apply plugin: 'java'

    // JDK 버전
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    // 컴파일 인코딩 옵션
    [compileJava, compileTestJava, javadoc]*.options*.encoding = "UTF-8"

    // 컴파일 옵션
    compileJava {
        options.compilerArgs << '-Xdoclint:none'
        options.fork = true
        options.forkOptions.executable = 'javac'
    }

    // 의존성 라이브러리 저장소
    repositories {
        jcenter()
    }

    // Spring Dependency Management Plugin을 사용
    apply plugin: 'io.spring.dependency-management'

    // Spring IO Platform 버전 지정
    // Gradle에는 원래 정의 되지 않은 task 이지만 io.spring.dependency-management plugin 적용으로 새롭게 생긴 task 이며 Spring IO Platform의 버전을 선언 하게 됩니다.
    dependencyManagement {
        imports {
            // Spring Dependency Management의 버전을 지정 하여 관련 의존성 라이브러리 버전을 같이 관리함.
            mavenBom 'io.spring.platform:platform-bom:1.1.2.RELEASE'
        }
    }

    // 하위 프로젝트 src/main/java, src/main/resources, src/test/java, src/test/resources 폴더 만들기
    task initSrc << {
        project.sourceSets*.allSource.srcDirTrees.flatten().dir.each { dir ->
            if (project.name.contains("-") && !project.name.equals(rootProject.name)) {
                dir.mkdirs()
            }
        }
    }
}

그리고 자바 기본 디렉토리 구조를 자동으로 생성 하려고 합니다.

    // 하위 프로젝트 src/main/java, src/main/resources, src/test/java, src/test/resources 폴더 만들기
    task initSrc << {
        project.sourceSets*.allSource.srcDirTrees.flatten().dir.each { dir ->
            if (project.name.contains("-") && !project.name.equals(rootProject.name)) {
                dir.mkdirs()
            }
        }
    }
    .... 이하 생략

전체 프로젝트에 대해 자바 소스 폴더를 각각 만들어 준다는 건 너무 귀찮고 힘들기 때문에 initSrc task를 하나 만들고 gradlew initSrc를 실행 하여 프로젝트별로 기본 폴더를 자동으로 생성 합니다.



그리고 처음에 얘기 했던 라이브러리 충돌 문제, 라이브러리 캐쉬 문제 처리를 넣어 줍니다.


allprojects {
// .. ...
    configurations {
        all {
            // 제외 처리 필요한 라이브러리 파일 설정
            exclude group: 'commons-logging'
            exclude module: 'slf4j-log4j12'
            resolutionStrategy {
                // 라이브러리 버전 충돌시 에러 경고
                failOnVersionConflict()
                // 모듈 변경 라이브러리 버전(SNAPSHOT) 캐쉬 없음
                cacheChangingModulesFor 0, 'seconds'
                // 동적 버전 라이브러리 버전은 10분만 캐쉬
                cacheDynamicVersionsFor 10 * 60, 'seconds'
            }
        }
    }
// .. ...
}

failOnVersionConflict, cacheChangingModulesFor , cacheDynamicVersionsFor 를 통해 의존성 라이브러리 설정을 관리해야 합니다. 특히 failOnVersionConflict를 적용 하지 않으면 다음처럼 버전만 틀린 중복된 라이브러리가 엮이게 되어 문제가 될 수 있습니다.



그렇지만 failOnVersionConflict 가 선언 되어 있다면 빌드시 다음 처럼 미리 경고를 받을 수 있습니다.



경고 된 버전 중 프로젝트에 맞는 버전으로 하나만 사용 할 수 있도록 강제화 하여 줍니다.

allprojects {
    ...
    configurations.all {
        // 모듈 버전 강제 적용 - (Spring Dependency Management 미 사용시 사용 방법)
        resolutionStrategy.forcedModules = [
                "org.jboss.logging:jboss-logging:3.1.3GA"
        ]
    }
    
    ....
}
 ...
// 4. 의존성 라이브러리 설정
dependencyManagement {
    imports {
        // Spring Dependency Management의 버전을 지정 하여 관련 의존성 라이브러리 버전을 같이 관리함.
        mavenBom 'io.spring.platform:platform-bom:1.1.2.RELEASE'
    }
    dependencies {
        // 모듈 버전 강제 적용 - (Spring Dependency Management 사용시 사용 방법)
        dependency 'com.fasterxml.jackson.core:jackson-databind:2.4.6'
        dependency 'org.springframework.hateoas:spring-hateoas:0.17.0.RELEASE'
    }
}
 ....

전체 스크립트를 다시 보면 다음과 같습니다.

allprojects {

    // 인텔리J 적용
    apply plugin: 'idea'

    // 인테리J 모듈 설정 셋팅 선언
    idea {
        module {
            inheritOutputDirs = false
            outputDir = file("$buildDir/classes/main/")
            jdkName = '1.8'
            downloadJavadoc = true
            downloadSources = true
        }
    }

    configurations {
        all {
            // 제외 처리 필요한 라이브러리 파일 설정
            exclude group: 'commons-logging'
            exclude module: 'slf4j-log4j12'
            resolutionStrategy {
                // 라이브러리 버전 충돌시 에러 처리
                failOnVersionConflict()
                // 모듈 변경 라이브러리 버전(SNAPSHOT) 캐쉬 없음
                cacheChangingModulesFor 0, 'seconds'
                // 동적 버전 라이브러리 버전은 10분만 캐쉬
                cacheDynamicVersionsFor 10 * 60, 'seconds'
            }
        }
    }
}

configure(allprojects.findAll { allprojects -> allprojects.name.contains('-') }) {

    apply plugin: 'java'

    // JDK 버전
    sourceCompatibility = 1.8
    targetCompatibility = 1.8

    // 컴파일 인코딩 옵션
    [compileJava, compileTestJava, javadoc]*.options*.encoding = "UTF-8"

    // 컴파일 옵션
    compileJava {
        options.compilerArgs << '-Xdoclint:none'
        options.fork = true
        options.forkOptions.executable = 'javac'
    }

    // 의존성 라이브러리 저장소
    repositories {
        jcenter()
        mavenCentral()
    }

    // Spring Dependency Management Plugin을 사용
    apply plugin: 'io.spring.dependency-management'

    // Spring IO Platform 버전 지정
    // Gradle에는 원래 정의 되지 않은 task 이지만 io.spring.dependency-management plugin 적용으로 새롭게 생긴 task 이며 Spring IO Platform의 버전을 선언 하게 됩니다.
    dependencyManagement {
        imports {
            // Spring Dependency Management의 버전을 지정 하여 관련 의존성 라이브러리 버전을 같이 관리함.
            mavenBom 'io.spring.platform:platform-bom:1.1.2.RELEASE'
        }
        dependencies {
            // 모듈 버전 강제 적용 - (Spring Dependency Management 사용시 사용 방법)
            dependency 'com.fasterxml.jackson.core:jackson-databind:2.4.6'
            dependency 'org.springframework.hateoas:spring-hateoas:0.17.0.RELEASE'
        }
    }

    // 하위 프로젝트 src/main/java, src/main/resources, src/test/java, src/test/resources 폴더 만들기
    task initSrc << {
        project.sourceSets*.allSource.srcDirTrees.flatten().dir.each { dir ->
            if (project.name.contains("-") && !project.name.equals(rootProject.name)) {
                dir.mkdirs()
            }
        }
    }
}

task wrapper(type: Wrapper) {
    description = "Generatres gradlew[.bat] scripts"
    gradleVersion = "2.3.10"
}

전체 프로젝트에 적용 할 기본 적인 의존성설정관리 중 allprojects 설정에 필요한 default.gradle 파일이 완료 되었습니다.

그럼 이 파일을 기존 파일과 같이 설정 하려면 다음과 같이 build.grdle에 적용 합니다.

// 1. buildScript 선언
// Gradle에서 제공 되는 빌드 기능 이외의 직접 만든 Plugin 기능이나 외부 기능(외부 라이브러리)을 사용하고자 한다면 추가로 정의
buildscript {
    .. 생략
    dependencies {
        classpath 'io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE'
    }
}

// 위에서 만들었던 파일을 적용 합니다.
apply from: "${gradleScriptDir}/default.gradle"

project('foundation:sample-boot-config') {
    dependencies {
        // Spring Boot
        compile 'org.springframework.boot:spring-boot-starter'
        // Lombok
        compile 'org.projectlombok:lombok:$lombokVersion'
    }
}

project('foundation:sample-boot-web-config') {
.... 이하 생략


 다음 섹션에서는 environment.gradle을 통해 profiles 별로 properties 값들을 사용하는 방법에 대해 얘기 하겠습니다.


Sample Source Github Link

https://github.com/gmind7/gradle-with-springboot

Posted by G마인드

댓글을 달아 주세요

  1. 전투너구리 2016.03.24 19:31 신고 Address Modify/Delete Reply

    도움되었습니다.감사합니다.