• Escribir complementos personalizados de Gradle
• Creando un Fat Jar en Gradle
1. Información general
Gradle es un sistema de gestión de compilación basado en Groovy diseñado específicamente para compilar proyectos basados en Java.
Las instrucciones de instalación se pueden encontrar aquí.
2. Bloques de creación: proyectos y tareas
En Gradle, las compilaciones constan de uno o más proyectos y cada proyecto consta de una o más tareas.
Un proyecto en Gradle puede ser ensamblar un frasco , una guerra o incluso un archivo zip .
Una tarea es una sola pieza de trabajo. Esto puede incluir compilar clases o crear y publicar archivos Java / web.
Una tarea simple se puede definir como:
task hello { doLast { println 'Baeldung' } }
Si ejecutamos la tarea anterior usando el comando gradle -q hello desde la misma ubicación donde reside build.gradle , deberíamos ver el resultado en la consola.
2.1. Tareas
Los scripts de compilación de Gradle no son más que Groovy:
task toLower { doLast { String someString = 'HELLO FROM BAELDUNG' println "Original: "+ someString println "Lower case: " + someString.toLowerCase() } }
Podemos definir tareas que dependan de otras tareas. La dependencia de la tarea se puede definir pasando el argumento dependsOn: taskName en una definición de tarea:
task helloGradle { doLast { println 'Hello Gradle!' } } task fromBaeldung(dependsOn: helloGradle) { doLast { println "I'm from Baeldung" } }
2.2. Agregar comportamiento a una tarea
Podemos definir una tarea y mejorarla con algún comportamiento adicional:
task helloBaeldung { doLast { println 'I will be executed second' } } helloBaeldung.doFirst { println 'I will be executed first' } helloBaeldung.doLast { println 'I will be executed third' } helloBaeldung { doLast { println 'I will be executed fourth' } }
doFirst y doLast agregan acciones en la parte superior e inferior de la lista de acciones, respectivamente, y se pueden definir varias veces en una sola tarea .
2.3. Agregar propiedades de tarea
También podemos definir propiedades:
task ourTask { ext.theProperty = "theValue" }
Aquí, estamos configuración “theValue” como laPropiedad del ourTask tarea.
3. Gestión de complementos
Hay dos tipos de complementos en Gradle: script y binario.
Para beneficiarse de una funcionalidad adicional, cada complemento debe pasar por dos fases: resolución y aplicación.
Resolver significa encontrar la versión correcta del contenedor del complemento y agregarla a la ruta de clases del proyecto.
La aplicación de complementos es ejecutar Plugin.apply (T) en el proyecto .
3.1. Aplicación de complementos de script
En aplugin.gradle, podemos definir una tarea:
task fromPlugin { doLast { println "I'm from plugin" } }
Si queremos aplicar este complemento a nuestro archivo de proyecto build.gradle , todo lo que tenemos que hacer es agregar esta línea a nuestro build.gradle :
apply from: 'aplugin.gradle'
Ahora, la ejecución del comando de tareas de Gradle debería mostrar la tarea fromPlugin en la lista de tareas.
3.2. Aplicación de complementos binarios mediante complementos DSL
En el caso de agregar un complemento binario central, podemos agregar nombres cortos o una identificación de complemento:
plugins { id 'application' }
Ahora la tarea de ejecución desde el complemento de la aplicación debería estar disponible en un proyecto para ejecutar cualquier jar ejecutable . Para aplicar un complemento de la comunidad, tenemos que mencionar un ID de complemento totalmente calificado:
plugins { id "org.shipkit.bintray" version "0.9.116" }
Ahora, las tareas de Shipkit deberían estar disponibles en la lista de tareas de Gradle .
Las limitaciones de los complementos DSL son:
- No admite el código Groovy dentro del bloque de complementos
- El bloque de complementos debe ser la declaración de nivel superior en los scripts de compilación del proyecto (solo se permite el bloque buildscripts {} antes)
- Los complementos DSL no se pueden escribir en el complemento de scripts, el archivo settings.gradle o en los scripts de inicio
Los complementos DSL aún se están incubando. El DSL y otras configuraciones pueden cambiar en las versiones posteriores de Gradle.
3.3. Procedimiento heredado para aplicar complementos
También podemos aplicar complementos usando el "aplicar complemento" :
apply plugin: 'war'
Si necesitamos agregar un complemento de comunidad, tenemos que agregar el jar externo a la ruta de clases de compilación usando el bloque buildscript {} .
Then, we can apply the plugin in the build scripts butonly after any existing plugins{} block:
buildscript { repositories { maven { url "//plugins.gradle.org/m2/" } } dependencies { classpath "org.shipkit:shipkit:0.9.117" } } apply plugin: "org.shipkit.bintray-release"
4. Dependency Management
Gradle supports very flexible dependency management system, it's compatible with the wide variety of available approaches.
Best practices for dependency management in Gradle are versioning, dynamic versioning, resolving version conflicts and managing transitive dependencies.
4.1. Dependency Configuration
Dependencies are grouped into different configurations. A configuration has a name and they can extend each other.
If we apply the Java plugin, we'll have compile, testCompile, runtime configurations available for grouping our dependencies. The default configuration extends “runtime”.
4.2. Declaring Dependencies
Let's look at an example of adding some dependencies (Spring and Hibernate) using several different ways:
dependencies { compile group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE' compile 'org.springframework:spring-core:4.3.5.RELEASE', 'org.springframework:spring-aop:4.3.5.RELEASE' compile( [group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'], [group: 'org.springframework', name: 'spring-aop', version: '4.3.5.RELEASE'] ) testCompile('org.hibernate:hibernate-core:5.2.12.Final') { transitive = true } runtime(group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final') { transitive = false } }
We're declaring dependencies in various configurations: compile, testCompile, and runtime in various formats.
Sometimes we need dependencies that have multiple artifacts. In such cases, we can add an artifact-only notations @extensionName (or ext in the expanded form) to download the desired artifact:
runtime "org.codehaus.groovy:groovy-all:[email protected]" runtime group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.11', ext: 'jar'
Here, we added the @jar notation to download only the jar artifact without the dependencies.
To add dependencies to any local files, we can use something like this:
compile files('libs/joda-time-2.2.jar', 'libs/junit-4.12.jar') compile fileTree(dir: 'libs', include: '*.jar')
When we want to avoid transitive dependencies,we can do it on configuration level or on dependency level:
configurations { testCompile.exclude module: 'junit' } testCompile("org.springframework.batch:spring-batch-test:3.0.7.RELEASE"){ exclude module: 'junit' }
5. Multi-Project Builds
5.1. Build Lifecycle
In the initialization phase, Gradle determines which projects are going to take part in a multi-project build.
This is usually mentioned in settings.gradle file, which is located in the project root. Gradle also creates instances of the participating projects.
In the configuration phase, all created projects instances are configured based on Gradle feature configuration on demand.
In this feature, only required projects are configured for a specific task execution. This way, configuration time is highly reduced for a large multi-project build. This feature is still incubating.
Finally, in the execution phase, a subset of tasks, created and configured are executed. We can include code in the settings.gradle and build.gradle files to perceive these three phases.
In settings.gradle :
println 'At initialization phase.'
In build.gradle :
println 'At configuration phase.' task configured { println 'Also at the configuration phase.' } task execFirstTest { doLast { println 'During the execution phase.' } } task execSecondTest { doFirst { println 'At first during the execution phase.' } doLast { println 'At last during the execution phase.' } println 'At configuration phase.' }
5.2. Creating Multi-Project Build
We can execute the gradle init command in the root folder to create a skeleton for both settings.gradle and build.gradle file.
All common configuration will be kept in the root build script:
allprojects { repositories { mavenCentral() } } subprojects { version = '1.0' }
The setting file needs to include root project name and subproject name:
rootProject.name = 'multi-project-builds' include 'greeting-library','greeter'
Now we need to have a couple of subproject folders named greeting-library and greeter to have a demo of a multi-project build. Each subproject needs to have an individual build script to configure their individual dependencies and other necessary configurations.
If we'd like to have our greeter project dependent on the greeting-library, we need to include the dependency in the build script of greeter:
dependencies { compile project(':greeting-library') }
6. Using Gradle Wrapper
If a Gradle project has gradlew file for Linux and gradlew.bat file for Windows, we don't need to install Gradle to build the project.
If we execute gradlew build in Windows and ./gradlew build in Linux, a Gradle distribution specified in gradlew file will be downloaded automatically.
If we'd like to add the Gradle wrapper to our project:
gradle wrapper --gradle-version 4.2.1
The command needs to be executed from the root of the project. This will create all necessary files and folders to tie Gradle wrapper to the project. The other way to do the same is to add the wrapper task to the build script:
task wrapper(type: Wrapper) { gradleVersion = '4.2.1' }
Ahora necesitamos ejecutar la tarea contenedora y la tarea vinculará nuestro proyecto al contenedor. Además de los archivos gradlew , se genera una carpeta contenedora dentro de la carpeta gradle que contiene un archivo jar y un archivo de propiedades.
Si queremos cambiar a una nueva versión de Gradle, solo necesitamos cambiar una entrada en gradle- wrapper.properties .
7. Conclusión
En este artículo, echamos un vistazo a Gradle y vimos que tiene una mayor flexibilidad sobre otras herramientas de compilación existentes en términos de resolución de conflictos de versiones y gestión de dependencias transitivas.
El código fuente de este artículo está disponible en GitHub.
Siguiente » Ant vs Maven vs Gradle