둘 다 외부 라이브러리의 의존성 관리와 빌드 과정을 자동화 해주는 빌드 도구이지만 서로 다른 접근 방식과 기능을 제공함
프로그램을 실행 가능한 배포 파일로 만드는 것
즉, 소스 코드를 컴파일하고, 컴파일된 클래스 파일과 리소스 파일 등 프로그램 실행에 관련된 파일들을 패키징 하여, 배포 가능한 형태로 만드는 것을 의미합니다.
위의 빌드 과정을 자동화 해주는 소프트웨어입니다. 설정 파일을 통해 필요한 작업을 정의하고 클릭 한 번으로 모든 의존 라이브러리(jar 파일)을 다운로드해 컴파일하고, 테스트하고, 패키징 하여 배포까지 자동으로 처리할 수 있습니다.
빌드 도구는 Ant -> Maven -> Gradle 순으로 발전되어 왔고
현재 JAVA 생태계에서 대표적으로 사용하는 빌드 도구가 바로 Maven과 Gradle입니다.
Maven은 Java 프로젝트를 위한 빌드 자동화 도구로, 빌드(Build), 패키징(jar 또는 war 파일 생성), 테스트, 외부 라이브러리 관리, 배포 등을 한 번의 명령으로 간편하게 처리할 수 있습니다.-
Maven은 이러한 Ant의 단점을 보완해서 외부 라이브러리가 자동으로 다운로드되고 관리할 수 있는 기능을 제공합니다. 더불어 표준화된 프로젝트 구조와 빌드 방식을 지원해 빌드 작업을 더욱 간소화하고 효율적으로 만들어 줍니다.
자동으로 빌드 및 테스트, 패키징을 자동으로 수행해주어서 개발 생산성이 향상되었습니다.
Maven은 POM.xml(Project Object Model) 파일을 사용해 빌드 설정을 관리합니다.
프로젝트의 필수적인 내용 ( 명칭 버전, 의존성 등 ) 부터 빌드와 관련된 세팅이나 추가적인 정보들이 모두 기입된다.
POM.xml 예시
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.osc</groupId>
<artifactId>test-simulation</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>test-simulation</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
// 사용할 dependency를 나열한다.
// 각종 dependency는 https://mvnrepository.com/ 통해 검색이 가능하다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Gradle은 2007년 JetBrains회사의 Hans Dockter가 개발한 오픈 소스 빌드 자동화 도구로 Apache Ant와 Apache Maven의 장점을 결합하여 만듬
buildscript {
ext {
springBootVersion = '2.3.7.RELEASE'
lombokVersion = '1.18.10'
}
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group 'gradle.test.javaapp'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
// api '...'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly "org.projectlombok:lombok:$lombokVersion"
// runtimeOnly '...'
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
}
repositories
, dependencies
를 따로 구현해야함.)$전역변수명
으로 사용할 수 있다.compile
의 경우 Gradle 3.0부터는 사용안하는 것을 권장(api
로 대체)A(api) <- B <- C 로 의존하는 구조라면, A 수정 시 B,C 모두 빌드
A(implementation) <- B <- C 로 의존하는 구조라면, A 수정 시 B 만 빌드
ex.) lombok, queryDSL 등
Gradle 프로젝트는 Maven과 유사한 폴더 구조를 가지고 있습니다. Gradle 프로젝트의 폴더 구조에는 gradle 디렉토리가 있으며, 이 안에는 Gradle 빌드 시스템의 버전을 관리하는 파일이 포함됩니다.
또한, 프로젝트 루트 디렉토리에는 gradlew 및 gradlew.bat 파일이 있어서 해당 프로젝트의 Gradle 빌드를 실행하는 데 사용됩니다.
Maven은 2004년에 처음 개발되어서, 현재까지 가장 많은 사용자가 사용하는 빌드 도구입니다.
반면 Gradle은 maven보다 나중에 개발된 빌드 도구로 2007년에 개발되었습니다. 처음에는 비교적 주목을 받지 못했지만, 2013년 구글이 안드로이드 스튜디오의 기본 빌드 시스템으로 Gradle을 채택해서, 안드로이드 개발자 사이에서는 Gradle이 표준 빌드 도구로 자리잡게 되었습니다.
지금도 구글 트렌드 지수는 Maven이 높습니다. 협업의 편리성과, 러닝 커브를 고려했을 때도 역시 Maven을 사용하는 팀이 많은걸로 예상합니다.
최근 1년간 구글 트렌드 분석 결과를 보면 다음과 같다.
놀랍게도 maven이 8:2 정도로 압도적으로 많은 비율을 보여준다. 미국도 마찬가지다.
하지만 우리나라 데이터를 보면 5:5 정도로 gradle이 살짝 우세한 그래프를 보여준다.
물론 이러한 트렌드는 Maven이 여전히 더 널리 사용되고 있음을 보여주지만, 이는 단순 검색량일 뿐 실제 사용성을 완벽하게 반영하지는 않습니다. Gradle 사용자들도 Maven 저장소나 POM 파일 관련 검색을 자주 하기 때문입니다.
https://discuss.gradle.org/t/gradle-popularity-vs-maven/36932
결론 : Gradle 쓰는게 좋아보인다.
프로젝트 코드가 빌드될 때 의존성 모듈도 함께 빌드될 수 있도록 Gradle에 해당 모듈을 찾을 수 있는 위치를 알려주어야 한다. 여기서 모듈을 저장하는 위치를 리포지토리라고 한다. 빌드에 대한 리포지토리를 선언하면 Gradle은 모듈을 찾고 검색한다. 리포지토리는 로컬 디렉토리 또는 원격 리포지토리 등 다양한 형태로 제공될 수 있다.
런타임에 Gradle은 선언된 의존성 찾고, 원격 저장소에서 다운로드하거나 로컬 디렉토리에서 검색하거나 멀티 프로젝트 설정에서 다른 프로젝트를 빌드할 수도 있습니다. 이 프로세스를 의존성 해결(dependency resolution)이라고 한다.
의존성이 해결(resolution)되면 해결(resolution) 메커니즘은 의존성의 기본 파일을 의존성 캐시라고도 하는 로컬 캐시에 저장한다. 향후 빌드에서는 불필요한 네트워크 호출을 피하기 위해 캐시에 저장된 파일을 재사용한다.
모듈은 추가 메타데이터를 제공할 수 있다. 메타데이터는 리포지토리에서 모듈을 찾기 위한 좌표, 프로젝트 또는 작성자에 대한 정보 등 모듈을 더 자세히 설명하는 데이터이다. 메타데이터에는 모듈이 제대로 작동하기 위해 다른 모듈이 필요하다는 것을 정의할 수 있다. Gradle은 전이 의존성이라고 하는 이러한 추가 모듈을 자동으로 해결(resolve)한다.
의존성 선언을 보기 전에 의존성 구성(dependency configuration)에 대한 개념을 정의할 필요가 있다.
Gradle 프로젝트에 선언된 모든 의존성은 특정 범위에만 적용된다. 예를 들어, 일부 의존성은 소스 코드를 컴파일하는 데 사용해야 하는 반면 다른 의존성은 런타임에만 사용할 수 있어야 한다. Gradle은 구성을 통해 의존성의 범위를 명시한다. 모든 구성은 고유한 이름으로 식별할 수 있다.
많은 Gradle 플러그인은 프로젝트에 사전 정의된 구성을 추가한다. 예를 들어 java 플러그인은 소스 코드 컴파일, 테스트 실행 등에 필요한 다양한 클래스 경로를 나타내는 구성을 추가한다.
구성은 다른 구성을 확장하여 상속 계층 구조를 형성할 수 있다. 하위 구성은 상위 구성에 대해 선언된 전체 의존성 집합을 상속한다.
구성 상속은 Java 플러그인과 같은 Gradle 핵심 플러그인에서 많이 사용된다. 예를 들어 testImplementation
은 implementation
구성을 확장한다. 여기에는 실용적인 목적이 있다. 테스트를 컴파일하려면 테스트 클래스를 작성하는 데 필요한 의존성 위에 테스트 대상 소스 코드의 의존성이 필요하다. 구성 상속은 Configuration.extendsFrom(org.gradle.api.artifacts.Configuration[])
메소드를 호출하여 형성된다.
// build.gradle
configurations {
smokeTest.extendsFrom testImplementation
}
dependencies {
testImplementation 'junit:junit:4.13'
smokeTest 'org.apache.httpcomponents:httpclient:4.5.5'
}
DependencyHandler는 의존성을 선언하는 데 사용된다. 의존성은 구성(configurations)으로 그룹화된다.
구성에 대한 특정 의존성을 선언하려면 다음 구문을 사용하면 된다.
dependencies {
configurationName dependencyNotation
}
아래 예시는 의존성을 선언하는 기본적인 방법을 보여준다.
plugins {
id 'java' // dependencies에 'implementation', 'testImplementation' 을 사용하기 위해
}
dependencies {
//for dependencies found in artifact repositories you can use
// 아티팩트 리포지토리에서 찾은 의존성의 경우 다음을 사용할 수 있다.
//the group:name:version notation
implementation 'commons-lang:commons-lang:2.6'
testImplementation 'org.mockito:mockito:1.9.0-rc1'
//map-style 표기법:
implementation group: 'com.google.code.guice', name: 'guice', version: '1.0'
//임의의 파일을 의존성으로 선언하기
implementation files('hibernate.jar', 'libs/spring.jar')
//'libs'의 모든 jars를 컴파일 클래스 경로에 넣기
implementation fileTree('libs')
}
https://www.elancer.co.kr/blog/detail/270
maven과 gradle 차이를 잘 모르고 썼었는데 정리가 잘 되어있군요!!
gradle이 편해서 더 많이 이용할 줄 알았는데 maven 사용량이 많아서 놀랐습니다.
잘 보고 갑니다