Maven, Gradle

뾰족머리삼돌이·2024년 1월 25일
0

WEB

목록 보기
7/10

Spring 프로젝트를 생성해주는 사이트 또는 IDE를 이용하여 프로젝트를 생성하려고하면 MavenGradle을 선택해야하는 순간이 온다

프로젝트를 진행하면서 Maven 또는 Gradle을 통하여 주로 의존성관리를 하게된다
이번에는 좀 더 자세하게 이것들을 살펴보려고 한다

빌드도구

Maven과 Gradle은 모두 빌드도구다

Apache Maven is a software project management and comprehension tool.

Gradle Build Tool is a fast, dependable, and adaptable open-source build automation tool with an elegant and extensible declarative build language.

여기서 빌드란 작성한 소스코드를 실행할 수 있는 상태로 만드는 작업을 의미한다
즉, Java의 경우 jar파일을 생성하는 작업이라고 볼 수 있다

이렇게 생성된 빌드파일은 서버에서 동작시는 과정 ( 배포 ) 에서 사용된다


Maven

Maven은 Apache 재단에서 만든 빌드도구로 프로젝트 객체 모델 ( POM )을 기반으로 한다
지식의 축적자라는 의미를 가지고있으며, 자카르타 프로젝트의 빌드 프로세스를 단순화하기 위해 만들어졌다

자카르타 프로젝트(Jakarta Project)는 자바 플랫폼을 위한 오픈 소스 소프트웨어를 만들고 정비하는 프로젝트이다, 위키백과

간단하게 말하자면 자바 기반 프로젝트를 쉽게 빌드하고 관리하기 위한 프로젝트

프로젝트 실행 이전에 테스트 코드를 미리 실행시켜주거나
프로젝트에 필요한 의존성을 관리해주거나
로그를 출력해주거나

하는 등의 작업을 해준다

주요 특징으로는 아래의 것들이 있다

  • 손쉬운 프로젝트 환경구성 ( 자주 사용되는 틀을 제공해준다 )
  • 일관된 사용방법
  • 자동업데이트와 같은 종속성 ( 의존성 ) 관리
  • 여러 프로젝트를 동시에 쉽게 작업
  • Ant task를 통한 의존성 관리나 배포
  • 자바나 스크립트 언어를 통한 플러그인 작성

기타등등

POM ( Project Object Model )

앞서 Maven은 POM을 기반으로 한다고 설명했다
실제로 Maven과 관련하여 설정을 할때 pom.xml이라는 파일을 이용한다

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <!-- 기본적인 내용  -->
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>...</version>
  <packaging>...</packaging> 
  <dependencies>...</dependencies> 
  <parent>...</parent>
  <dependencyManagement>...</dependencyManagement>
  <modules>...</modules>
  <properties>...</properties>
 
  <!-- 빌드 세팅 -->
  <build>...</build>
  <reporting>...</reporting>
 
  <!-- 추가적인 프로젝트 정보 -->
  <name>...</name>
  <description>...</description>
  <url>...</url>
  <inceptionYear>...</inceptionYear>
  <licenses>...</licenses>
  <organization>...</organization>
  <developers>...</developers>
  <contributors>...</contributors>
 
  <!-- 환경 설정  -->
  <issueManagement>...</issueManagement>
  <ciManagement>...</ciManagement>
  <mailingLists>...</mailingLists>
  <scm>...</scm>
  <prerequisites>...</prerequisites>
  <repositories>...</repositories>
  <pluginRepositories>...</pluginRepositories>
  <distributionManagement>...</distributionManagement>
  <profiles>...</profiles>
</project>

pom.xml의 전체적인 구성은 위와 같다
프로젝트의 필수적인 내용 ( 명칭 버전, 의존성 등 ) 부터 빌드와 관련된 세팅이나 추가적인 정보들이 모두 기입된다

내용이 많으므로 간략하게 기본적인 내용과 빌드 설정부분만 설명할 예정이다
자세한 내용은 공식문서를 확인하자


기본적인 내용

<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>

groupId:artifactId:version의 꼴로 프로젝트 진행자, 프로젝트 명칭, 버전을 표기하는데 사용된다

이는 IntellJ 등을 통해 프로젝트를 생성할 때 입력할 수 있다

이렇게 생성된 프로젝트는 빌드 시 프로젝트 명칭과 버전이 표기된 jar파일을 생성한다


<packaging>...</packaging>

간단하게 jarwar중 어떤 방식으로 패키징할 것인지를 선택하는 옵션이다

Jar => 자바 애플리케이션이 동작할 수 있도록 압축한 파일
War => Servlet/JSP와 같은 웹자원을 포함하여 압축한 파일
참고


<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <type>jar</type>
    <scope>test</scope>
    <optional>true</optional>
  </dependency>
  ...
</dependencies>

외부 의존성 목록을 작성하는 영역이다
주로 mvn repository 를 이용해서 의존성을 얻어온다

이곳에 작성한 의존성은 Maven이 다운로드해서 관리한다 ( users/{}/.m2/repository )

scope는 해당 의존성의 동작범위를 지정하는데 사용된다

compile, provided, runtime, test, system 이 존재한다
compile => 기본 설정, 모든 클래스에서 사용가능
provided => 패키징시 제외
runtime => 컴파일시에는 불필요
test => 테스트 과정에서만 필요
system => 명시적으로 jar파일을 포함해야한다는 것을 의미, ex: 직접만든 의존성파일

optional은 다른 의존성에서 이미 해당 의존성을 사용중이기 때문에 설치할 필요가 없음을 표기하는데 사용된다


<parent>...</parent>
<dependencyManagement>...</dependencyManagement>

parentdependencyManagement는 일종의 상속관계( 부모-자식 )에서 사용되는 옵션이다
두 프로젝트 관계를 이어줄 때 사용할 수 있으며 자식 프로젝트의 pom.xml에 부모 프로젝트의 정보를 작성해야한다

부모-자식 관계에서는 의존성이 전이되는데 이때 dependenciesdependencyManagement의 동작이 다르다

dependencies의 경우 자식 프로젝트가 항상 해당 의존성을 가지게 된다
반면 dependencyManagement의 경우 자식 프로젝트에서 dependencies에 동일한 의존성을 작성한 경우에만 의존성을 가진다

또한 dependencyManagement에 의존성과 관련된 정보( 버전 )을 명시함으로써 해당 의존성을 필요로하는 자신 또는 하위 프로젝트들이 dependencies를 작성할때 버전정보를 작성하지 않아도 된다. 즉, 버전관리를 한곳에서 처리할 수 있다


<modules>
  <module>my-project</module>
  <module>another-project</module>
  <module>third-project/pom-example.xml</module>
</modules>

modules는 일종의 프로젝트 집합을 만드는 용도로 사용되며, 이 경우 의존성은 현재 pom.xml을 기준으로 먼저 적용된다
모듈또한 상속과 유사하게 현재 프로젝트에서 관리할 수 있는 하위모듈을 지정하는 것을 의미한다
이를 통하여 하나의 프로젝트에서 여러개의 모듈을 관리하는 것이 가능하다. 즉, 하나의 pom.xml을 이용하여 하위 프로젝트 또는 모듈의 의존성을 관리하는 것 또한 가능하다


<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.7</maven.compiler.source>
  <maven.compiler.target>1.7</maven.compiler.target>
</properties>

마지막으로 properties는 환경변수를 지정하는데 사용된다
${ name } 의 꼴로 사용이 가능하며, pom.xml에서 사용할 전역변수를 설정한다고 보면된다


빌드세팅

<build>
  <defaultGoal>install</defaultGoal>
  <directory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/target</directory>
  <finalName>${artifactId}-${version}</finalName>
  <filters>
    <filter>filters/filter1.properties</filter>
  </filters>
  ...
</build>

빌드과정에 필요한 정보들을 설정하는 영역이다
기본적인 구성은 위에 작성한 것과 동일하다

defaultGoal : 아무것도 주어지지 않았을때 실행될 작업을 설정한다 ( install, clean, build 등 )
directory : 빌드시 생성되는 파일의 위치를 의미한다
finalName : 빌드 시 생성되는 프로젝트 이름이다
filters : *.properties로 정의된 파일에 설정된 자원들을 허락하는 용도로 사용된다
설정된 파일에 만약 name=test 라고 작성되어 있다면, application.properties에서 ${name}을 이용하여 사용할 수 있다


<build>
  ...
  <resources>
    <resource>
      <targetPath>META-INF/plexus</targetPath>
      <filtering>false</filtering>
      <directory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/src/main/plexus</directory>
      <includes>
        <include>configuration.xml</include>
      </includes>
      <excludes>
        <exclude>**/*.properties</exclude>
      </excludes>
    </resource>
  </resources>
  <testResources>
    ...
  </testResources>
  ...
</build>

앞서 소개한 것들에 이어서 resources ( 주로 *.propertis 또는 *.yml ) 관련 설정을 할 수 있다

resources: 프로젝트와 관련된 resource들을 표시하는데 사용
targetPath: 빌드에서 생성될 resource파일들의 경로를 작성
filtering: filter의 사용유무를 작성
directory: resource를 찾는 위치를 작성
includes: resource로 포함할 패턴
excludes: resource로 제외할 패턴
testResources: 테스트시 사용될 resource 설정


<build>
  ...
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jar-plugin</artifactId>
      <version>2.6</version>
      <extensions>false</extensions>
      <inherited>true</inherited>
      <configuration>
        <classifier>test</classifier>
      </configuration>
      <dependencies>...</dependencies>
      <executions>...</executions>
    </plugin>
  </plugins>
</build>

마지막으로 pluginmaven 동작의 핵심이다
모든 작업은 plugin을 통해 이루어지며 관련 정보는 여기를 확인해보자

extensions : 해당 플러그인의 extension의 사용유무
inherited : 해당 구성을 상속하는 pom.xml에서의 적용유무를 설정
configuration : 개인 플러그인과 관련된 설정,
dependencies : 플러그인과 관련된 의존성 설정
executions : 플러그인이 목표를 특정단계에 바인딩하는 것과 관련된 설정

<executions>
  <execution>
    <id>echodir</id>
    <goals>
      <goal>run</goal>
    </goals>
    <phase>verify</phase>
    <inherited>false</inherited>
    <configuration>
      <tasks>
        <echo>Build Dir: /home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/target</echo>
      </tasks>
    </configuration>
  </execution>
</executions>

verify 단계에 run이라는 목표를 바인딩하는 설정


<build>
    <sourceDirectory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/src/main/java</sourceDirectory>
    <scriptSourceDirectory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/src/main/scripts</scriptSourceDirectory>
    <testSourceDirectory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/src/test/java</testSourceDirectory>
    <outputDirectory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/target/classes</outputDirectory>
    <testOutputDirectory>/home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/target/test-classes</testOutputDirectory>
    ...
</build>

자바 소스파일의 위치나 컴파일시 생성될 파일의 위치를 표시하는데 사용되는 옵션이다


Gradle

Gradle은 빌드 스크립트를 이용해서 빌드, 테스트, 배포등을 자동화한다
Gradle의 build.gradle는 Maven의 pom.xml과 유사한 동작을 한다

settings.gradlebuild.gradle을 이용하여 프로젝트와 관련된 의존성이나 Task를 설정하고 이를 통하여 손쉽게 실행할 수 있다

Gradle은 크게 User Home DirectoryProject Root Directory로 나뉜다

User Home Directory에서는 전역적인 propertie 설정이나 초기화 스크립트, 캐시나 로그파일 등이 저장된다
일반적으로 C:\Users\<USERNAME>\.gradle 에 위치하고 있으며 GRADLE_USER_HOME 환경변수로 저장해서 이용할 수도 있다

init.d 하위에 초기화 스크립트가 존재한다

Project Root Directory는 흔히 만드는 프로젝트 폴더를 의미한다
이곳에는 .gradlebuild폴더가 포함된다

.gradle의 경우 버전관리와 관련된 정보
build에는 주로 빌드 결과물이 저장된다

또한 Gradle Wrappersettings.gradle, build.gradle 파일이 존재한다

settings.gradle의 경우 루트프로젝트에 위치하며 build.gradle은 서브프로젝트마다 존재한다


Build Lifecycle

Gradle의 빌드는 크게 초기화 - 설정 - 실행 의 단계를 거친다

초기화에서는 settings.gradle을 인식하고, Settings 인스턴스를 생성하며, 빌드를 구성할 프로젝트를 결정한다
또한 프로젝트마다 Project 인스턴스를 생성한다

설정에서는 초기화 단계에서 찾은 빌드에 참여하는 프로젝트들의 build.gradle에 있는 빌드 스크립트들을 확인한다

실행에서는 선택된 task들의 실행 순서를 설정하고, 작업간의 의존성에 따라 실행순서를 결정짓는다
또한 병렬적으로 task들을 실행시킨다


settings.gradle

초기화단계에서 settings.gradle를 찾게되면 빌드에 포함될 프로젝트를 설정하기 위하여 Settings 객체를 생성한다
이때 생성되는 객체는 해당 파일을 가지고 만들어진다

해당 객체에는 빌드 캐시설정, 관련 플러그인, 루트 디렉토리, 루트 프로젝트와 같은 기본적인 항목들이 존재하며, 하위 프로젝트에 대한 정보도 포함된다

이러한 설정들은 closure ( Groovy ) 또는 lambda ( Kotlin )라고 불리는 {} 블록을 통하여 작성한다
작성된 코드들은 top-bottom 의 순서대로 읽히여 실행된다

pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
    }
}

플러그인들의 위치를 설정하는 코드를 작성하는 코드이다
이곳에는 Gradle Plugin Portal과 같은 바이너리 저장소가 포함된다
또한 플러그인이나 플러그인 의존성 전략등을 포함시킬 수 있다

plugins {
   id("org.gradle.toolchains.fake") version "0.6.0"
}

또한 사용될 수도 있는 플러그인목록을 선언하는게 가능하다
이는 빌드에 포함되는 서브프로젝트에게도 공유된다

이를 통하여 하위프로젝트에서 동일한 버전의 플러그인을 사용하게 할 수 있다

dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
}

Maven Central을 포함하여, 프로젝트에 사용되는 의존성들의 위치를 설정하는 것도 가능하다

include("app")
include("business-logic")
include("data-model")

마지막으로 빌드에 포함될 하위 프로젝트들을 설정할 수 있다


build.gradle

설정단계에서 해당 파일을 읽고 Project 객체를 생성한다
해당 위치에도 마찬가지로 Groovy 또는 Kotlin 문법을 이용한 코드작성이 가능하다

기본적으로 프로젝트 폴더의 이름, 경로, 의존성 핸들러 들을 설정하는게 가능하다
추가적으로 task의 생성도 가능하다

작성되는 양식은 앞서 설명한 settings.gradle과 동일하게 {}를 이용한다


plugins {
    id("org.jetbrains.kotlin.jvm") version "1.9.0"
    id("application")
}

먼저 해당 프로젝트 빌드 시 적용될 플러그인 목록을 설정할 수 있다
이러한 플러그인들은 프로젝트 설정을 모듈화하고 재사용하는데 사용된다

application {                                                           
    mainClass = 'com.example.Main'
}

예를들어, applicaiton 플러그인을 통하여 프로젝트의 진입지점을 설정할 수 있다


repositories {
    mavenCentral()
    google()
}

settings.gradle과 유사하게 의존성을 가져오기위한 저장소의 위치를 설정하는 예시다


tasks.register("zip-reports", Zip) {
    from 'Reports/'
    include '*'
    archiveName 'Reports.zip'
    destinationDir(file('/dir'))
}

또한 task를 등록하거나 설정하는게 가능하다
위 예시에서는 register를 이용하여 zip-reports라는 task를 등록하고있다


tasks.named('test') {
	useJUnitPlatform()
}

Spring Boot에서는 기본적으로 테스트를 위한 Task 설정을 제공한다

의존성 관리

Version Catalog를 작성해서 하위 프로젝트간 의존성이나 버전구성을 공유할 수 있다
보통 libs.versions.toml라는 명칭으로 작성한다

[versions]
androidGradlePlugin = "7.4.1"
mockito = "2.16.0"

[libraries]
google-material = { g**텍스트**roup = "com.google.android.material", name = "material", version = "1.1.0-alpha05" }
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" }

[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }

4가지의 섹션 ( version, libraries, bundles, plugins)이 존재하며, 관련코드를 작성했다면 자동으로 IDE가 읽어서 설정해준다

dependencies {
    // Dependency on a remote binary to compile and run the code
    implementation(libs.google.material)    

    // Dependency on a remote binary to compile and run the test code
    testImplementation(libs.mockito.core)   
}

주로 사용하는 의존성의 관리는 dependencies 섹션에 작성할 수 있다
이곳에는 implementation, compileOnly, annotationProcessor, testImplementation 등을 설정할 수 있다

implementation의 경우, 컴파일 및 실행시에 필요한 의존성
compileOnly의 경우, 컴파일 시에만 필요한 의존성 ( ex: lombok )
annotationProcessor애노테이션 프로세서 설정
testImplementation는 테스트 코드의 컴파일과 실행에 필요한 의존성


Task

Task는 빌드시 수행될 작업단위를 의미한다
./gradlew {task 이름} 의 명령을 통해서 동작시키거나 IDE를 사용하여 동작시킬 수 있다

이러한 Task 간에는 의존성이 존재하기에 하나의 task를 실행시켰을때 다른 task들이 실행되게 할 수 있다

$ ./gradlew build

> Task :app:compileJava
> Task :app:processResources NO-SOURCE
> Task :app:classes
> Task :app:jar
> Task :app:startScripts
> Task :app:distTar
> Task :app:distZip
> Task :app:assemble
> Task :app:compileTestJava
> Task :app:processTestResources NO-SOURCE
> Task :app:testClasses
> Task :app:test
> Task :app:check
> Task :app:build

BUILD SUCCESSFUL in 764ms
7 actionable tasks: 7 executed

공식문서의 예시를 보면 이를 눈으로 확인할 수 있다


Plugin

플러그인은 빌드 기능을 확장하는데 주로 사용된다

예를들어 Spring Boot를 지원하기 위한 org.springframework.boot 플러그인이나 Java와 관련한 java 플러그인이 있다

이러한 플러그인은 크게 3가지로 Core, Commnunity, Local로 나뉜다

Core은 Gradle에서 제공하며 짧고 유일한 명칭을 가지고,
Commnunity는 플러그인 개발자들이 만들어 놓은 플러그인,
Local은 개인적으로 만든 플러그인을 의미한다

0개의 댓글