The dependency cache of Gradle tries to minimize the number of remote requests and downloads so that builds can be fast and reliable. The cache has two parts to perform proper dependency caching:
The separation of a metadata cache based on the repository and the artifact cache provides enough flexibility to perform repeatable and reliable dependency resolution. If the dependency metadata cannot be resolved by Gradle, then the dependency resolution will stop, even if the local cache has a copy of the artifact that was downloaded from a different repository (not defined in our build). This repository independence isolates builds from each other and prevents problems with dependency artifacts.
Gradle first tries to determine the SHA1 checksum for an artifact file before downloading the artifact. If the checksum can be determined, the file will not be downloaded if it is already in the cache with the same checksum. Gradle also tries to reuse artifacts from the local Maven repository. If the checksum for an artifact in the local Maven repository matches the checksum for the artifact from the remote repository, then the artifact doesn't need to be downloaded and can be copied from the local Maven repository.
Because Gradle uses an SHA1 checksum for the artifact contents, different versions for the same artifact can be stored. For example, when an artifact is part of a changing module or the contents of the artifact have changed in the repository without a change in the version number.
Both the metadata cache and artifact cache are stored in the directory defined by the GRADLE_USER_HOME
environment variable that is, by default, the .gradle/caches
directory in the user home directory. Gradle uses a sophisticated locking mechanism for the caches, so multiple projects can use the cache directories and files simultaneously. In the next example build file, we create the artifactsLocation
task to print out where the downloaded artifacts are stored:
apply plugin: 'java' repositories.jcenter() dependencies { compile 'org.slf4j:slf4j-api:1.7.7' runtime 'ch.qos.logback:logback-classic:1.1.2' } task artifactsLocation { description 'Show location of artifact on disk' doFirst { configurations.runtime.each { println it } } }
When we execute the artifactsLocation
task, we see in the output that the files are stored in the .gradle/caches
directory in the user home directory (/Users/mrhaki
). We also see the SHA1 checksums with which the directory names are used. The following code shows this:
$ gradle -q artifactsLocation /Users/mrhaki/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.7/2b8019b6249bb05d81d3a3094e468753e2b21311/slf4j-api-1.7.7.jar /Users/mrhaki/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.1.2/b316e9737eea25e9ddd6d88eaeee76878045c6b2/logback-classic-1.1.2.jar /Users/mrhaki/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-core/1.1.2/2d23694879c2c12f125dac5076bdfd5d771cc4cb/logback-core-1.1.2.jar
We can use the --offline
command-line option to skip any network requests. So, with this option, Gradle never tries to access remote repositories and all information is fetched from the Gradle dependency caches. If the information in the caches is not sufficient for a build, then the build fails.
With the --refresh-dependencies
option, we can refresh the metadata caches. If, for some reason, we expect the metadata to be no longer correct, we can use this option. Gradle will then refresh all information in the metadata caches for each repository. Artifacts are only downloaded when the SHA1 checksum is different than the checksum for artifacts in the artifacts cache.
A dependency with a static version can be easily cached. The contents of the artifact has a checksum, and this can be used to either use the cache or download the artifact (and place it in the artifact cache). A dependency with a dynamic version or changing module can have a changing artifact, so we need to be able to customize the cache settings. We can change the expiration time for cached dependencies with a dynamic version and changing modules. The default expiration time is 24 hours. After the expiration time, Gradle will invalidate the cache and determine whether an artifact needs to be downloaded again.
We change the expiration time for dependencies with a dynamic version using the cacheDynamicVersionsFor
method of the resolutionStrategy
configuration closure. The method accepts a number and time unit to set the value for the cache expiration. The time unit can be either of the java.util.concurrent.TimeUnit
type or a string that is converted to TimeUnit
.
To change modules, we use the cacheChangingModulesFor
method to change the expiration time. This method also accepts a number and time unit just as the cacheDynamicVersionsFor
method does.
In the next example build file, we change the cache expiration for both dynamic versions and changing modules for runtime
configurations. We can also set it for all configurations with the all
method and configuration block. The following code shows this:
// Import needed for cache methods time unit. import java.util.concurrent.TimeUnit apply plugin: 'java' repositories.jcenter() configurations { runtime { resolutionStrategy { // Change expiration time for caching // dynamic version to 30 minutes. cacheDynamicVersionsFor 30, 'minutes' // Alternative syntax is using TimeUnit: // cacheDynamicVersionsFor 1, TimeUnit.HOURS // Change expiration time for cached // changing modules to 5 minutes using // java.util.concurrent.TimeUnit. cacheChangingModulesFor 5, TimeUnit.MINUTES // Or we could use string notation. // cacheChangingModulesFor 1, 'minutes' } } // Alternatively we could apply // this to all configurations: // all { // resolutionStrategy { // cacheDynamicVersionsFor 4, 'hours' // cacheChangingModulesFor 10, 'minutes' // } // } } dependencies { compile 'org.slf4j:slf4j-api:1.7.7' runtime 'ch.qos.logback:logback-classic:1.1.2' }
Gradle knows about artifacts that are stored in a Maven repository, and that if the version attribute ends with -SNAPSHOT
, the module is a changing module. We can also define in our build script whether a dependency is a changing module, for example, if this cannot be derived from the version attribute. We must set the changing
property to the value true
in the configuration closure for a dependency.
In the following example build file, we have the com.vehicles:cars
dependency, which is a changing module, but we use the static version 1.0
:
apply plugin: 'java' repositories { maven { url 'http://ourcompany.com/maven' } } dependencies { compile('com.vehicles:cars:1.0') { // Instruct Gradle this a changing // module, although it cannot // be derived from the version attribute. changing = true } // Other syntax using the map notation: // compile group: 'com.vehicles', name: 'cars', // version: '1.0', changing: true }
3.129.42.243