在Gradle深化解析 – Task原理(履行篇)中分析过gradle的缓存机制,知道gradle有本地和长途缓存的区分,它会记载下task的输入输出,能够从缓存中康复输出来防止从头履行,以加速构建速度,那么咱们怎么来运用remote build cache部分呢?
运用remote build cache有2种办法
- docker或jar包的办法运转
- 自己写一个build cache service
2种办法有什么区别呢?
个人感觉第一种比较合适小团队,小团队人数不多,一同开发一个项目,docker运转服务在一个服务机器上就行,关于大型团队来说,每个项目都装备一次docker比较麻烦,也不容易将不同团队数据阻隔
自己写一个插件来完成build cache service能够解决这个问题,build cache service和自己的OSS服务器通讯,自己的OSS服务器能够阻隔不同团队(不同的团队恳求不同的Bucket),并且不同每次从头装备docker服务,只需要apply一下plugin,然后改一下装备即可,十分方便
本篇针对第二种办法进行解说,第一种办法能够参阅以下一些文章的相关部分
Build Cache Node User Manual | Gradle Enterprise Docs
运用本地和长途的Gradle构建缓存加速构建速度
Android-Studio编译速度优化
Using Gradle Build Cache Server
google androidx团队开源了一个GitHub – androidx/gcp-gradle-build-cache,便是利用Google Cloud Storage来完成这个需求的
可是国内最大的OSS服务商还是阿里云,这个插件不支持,于是我仿照它的完成写了一个基于阿里云OSS的插件GitHub – neas-neas/aliyun-gradle-build-cache,用法相似
下面咱们就从这个插件的用法打开,详细解说怎么创立一个阿里云OSS Bucket,怎么装备gradle文件,后面再简略测试一下作用讲起
再分析其完成具体完成进程,你也能够基于自己公司的OSS服务完成一个自己的build cache server
阿里云OSS有必定的免费额度,超越额度会收费,你能够在简略的项目里边测试
运用办法
1. 创立阿里云OSS Bucket
首先去阿里云OSS官网创立OSS Bucket oss.console.aliyun
点击立即创立开端创立Bucket,顺便记载一下endpoint和bucket name,没有记下来也没关系,后面能够在概览里边找到
然后在bucket页面找到权限控制 -> RAM拜访控制,前往RAM控制台
假如没有用户要先创立用户,至少勾选OpenAPI调用拜访
创立用户成功后会跳转到这个页面,这里需要记载下AccessKey ID和AccessKey Secret,后面封闭页面就获取不到了
用户创立完后,给用户添加权限
权限选中OSS相关的,保险起见FullAccess和ReadOnlyAccess都选上了,因为我之前都装备过了所以显示是灰色的
至此阿里云OSS的Bucket就创立完成了,现在就能够去项目中进行相关的装备
2. 装备gradle
在settings.gradle中添加如下装备,着重一下是settings,kts脚本相似这里就不列出来了
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'io.github.neas-neas:alibuildcache:1.0.0'
}
}
apply plugin: 'io.github.neas-neas.alibuildcache'
import io.github.neas.AliyunBuildCache
import io.github.neas.AliyunBuildCacheServiceFactory
import io.github.neas.ExportedAliyunCredentials
buildCache {
registerBuildCacheService(AliyunBuildCache, AliyunBuildCacheServiceFactory)
remote(AliyunBuildCache) {
endpoint = 'your-aliyun-oss-endpoint'
bucketName = "bucket-name"
credentials = new ExportedAliyunCredentials("your-access-key-id", "your-secret-key")
push = true //System.getenv().containsKey("CI")
}
}
新办法引入插件如下,见plugins.gradle.org/plugin/io.g…
plugins {
id("io.github.neas-neas.alibuildcache") version "1.0.0"
}
然后之前在创立Bucket时记载的信息这里就需要用上了
endpoint
bucketName
accessKeyId
secretKey
和咱们记载时的参数名字相同,不需要过多解说了,对座入号填入即可
照官方推荐push
只在CI机器上开,developer的机器拉缓存就行,不过为了测试咱们这里先改为true好了
3. 测试作用
所有都装备好了,咱们来测试一下看看情况
rm -r ~/.gradle/caches/build-cache-1
./gradlew clean build -i
rm删除去本地build cache缓存,因为咱们要看remote cache,本地缓存优先级更高,所以要扫除它
-i
能够在输出中看到相关日志
第一次履行,看看compileJava
输出
因为没有缓存,所以第一次履行会store到阿里云OSS
再履行一下上面的指令,再看看compileJava
的输出
因为没有本地缓存(被咱们提早rm了,不rm的话第一步履行时也会在本地进行保存的),咱们能够看到compileJava
task被符号为了FROM_CACHE,2次的cache key完全一致,并且日志输出了是从阿里云OSS下载下来的
有这个key,咱们也能够去阿里云OSS Bucket文件管理页面找到对应的文件,将它下载下来看看它究竟是什么
其实它便是个tar包压缩文件,能够进行解压看看里边究竟有什么,这个RemoteBuildCache
便是我测试项目里边的代码文件了,你也能够对你的class文件反编译看看是否一致。这部分在Gradle深化解析 – Task原理(履行篇)其实有讲过了
此外针对android项目建议一起运用上GitHub – gradle/android-cache-fix-gradle-plugin: Gradle plugin that fixes Android build caching problems,agp插件对cache的完成有些问题,这个插件能够规避一些此类的问题
具体完成
关系图暗示如下
核心办法
BuildCacheService
最首要的是完成BuildCacheService
这个接口,接口有2个十分关键的办法load
和store
public interface BuildCacheService extends Closeable {
boolean load(BuildCacheKey key, BuildCacheEntryReader reader) throws BuildCacheException;
void store(BuildCacheKey key, BuildCacheEntryWriter writer) throws BuildCacheException;
void close() throws IOException;
}
load
便是拿key去恳求OSS获取文件,然后将获取到的InputStream对接给reader
store
便是将文件保存到OSS,调用writer
的writeTo
办法将数据导入到咱们的OutputStream,再将OutputStream转为InputStream传给OSS服务器
阿里云OSS有提供SDK,按照其SDK文档就行对应办法调用即可
BuildCache
public interface BuildCache {
boolean isEnabled();
void setEnabled(boolean enabled);
boolean isPush();
void setPush(boolean enabled);
}
BuildCache是用于装备BuildCacheService
的,相似于写gradle plugin时的extension
默许有enabled
和push
2个参数
关于OSS来说还不够,以阿里云为例,还需要endpoint
、bucketName
、credentials
(首要用于装备accessKeyId
和secretAccessKey
)
咱们能够经过继承来完成自己的BuildCache类,比方
abstract class AliyunBuildCache(
) : AbstractBuildCache() {
lateinit var endpoint: String
var credentials: AliyunCredentials = DefaultAliyunCredentials
}
BuildCacheServiceFactory
public interface BuildCacheServiceFactory<T extends BuildCache> {
BuildCacheService createBuildCacheService(T configuration, Describer describer);
}
这个接口是用来创立BuildCacheService
,看看AliyunBuildCacheServiceFactory
的完成,调用describer
结合buildCache
进行一些描绘性质的装备,然后用buildCache
去创立AliyunBuildCacheService
实例
![[aliyun-gradle-plugin-factory.png]]
Describer
interface Describer {
Describer type(String type);
Describer config(String name, String value);
}
用于描绘BuildCacheService
type
网络恳求的是http,本地的是directory,自定义的比方我这里是aliyun
config
装备一些tag,例如bucketName的值,endpoint
这些信息能够被build scan插件搜集,关于判别缓存命中率有必定帮助
建立相关
需要在Plugin
里边去绑定关系
class AliyunGradleBuildCachePlugin : Plugin<Settings> {
override fun apply(settings: Settings) {
settings.buildCache.registerBuildCacheService(
AliyunBuildCache::class.java,
AliyunBuildCacheServiceFactory::class.java
)
}
}
留意这是一个针对Setting
的Plugin,调用registerBuildCacheService
注册BuildCache
和BuildCacheServiceFactory
之后就能够在settings.gradle
脚本对BuildCache
进行装备了,例如上面提到过的
buildCache {
remote(AliyunBuildCache) {
endpoint = 'your-end-point'
bucketName = "bucket-name"
credentials = new ExportedAliyunCredentials("your-access-key-id", "your-secret-key")
push = true
}
}
至此关于Build Cache的运用和原理大致都进行了阐明,Build Cache在实际运用中假如感觉作用欠安,那还需要从多个方面去提升它的缓存命中率,有几个对其命中率有影响的要素,例如履行gradle的JVM的版别不同,Java/Kotlin编译时的JVM版别不同,classpath改变等,可能需要经过build scan等构建信息搜集办法去进行具体分析,以提升缓存命中率。关于构建信息的搜集能够参阅我之前的怎么像build scan相同搜集gradle构建信息
参阅资料
GitHub – androidx/gcp-gradle-build-cache
Docker
运用本地和长途的Gradle构建缓存加速构建速度
Android-Studio编译速度优化
Using Gradle Build Cache Server. Fastest way to work is to avoid doing… | by Csar Ferreira | Medium
Build Cache Node User Manual | Gradle Enterprise Docs
GitHub – rnett/github-actions-gradle-cache