这个文章的基础是你基本已经完成了transfrom 的开发了,而后你碰到了编译速度慢的问题。
在Transform的抽象类中有一个isIncremental方法,这个方法就表明着是否开启增量编译。
ide
编译过程当中会去遍历全部的jar .class文件,而后对文件进行io操做,以及asm插入代码,这个过程耗时通常都会很长。
这里须要注意一点:不是每次的编译都是能够怎量编译的,毕竟一次clean build彻底没有增量的基础,因此,咱们须要检查当前的编译是否增量编译。
须要作区分:
不是增量编译,则清空output目录,而后按照前面的方式,逐个class/jar处理
增量编译,则要检查每一个文件的Status,Status分为四种,而且对四种文件的操做不尽相同
NOTCHANGED 当前文件不须要处理,甚至复制操做都不用
ADDED、CHANGED 正常处理,输出给下一个任务
REMOVED 移除outputProvider获取路径对应的文件
上述是对增量的一些定义,能够看出来在transfrom过程当中,应该是对文件打了一些tag标签。
那么咱们在开发阶段首先要先区分当前此次是否是增量编译,而后再编译当前变动的文件,对变动的文件进行处理。
优化
我在代码设计中,对transform进行了一次代码抽象,把文件操做进行了一次抽象,同时把扫描以及.class文件操做进行了一些基础封装,后续的开发就能够直接在这个的基础上进行后续快速迭代开发。
ui
public void startTransform() {
try {
if (!isIncremental) {
outputProvider.deleteAll();
}
for (TransformInput input : inputs) {
for (JarInput jarInput : input.getJarInputs()) {
Status status = jarInput.getStatus();
String destName = jarInput.getFile().getName();
/* 重名名输出文件,由于可能同名,会覆盖*/
String hexName = DigestUtils.md5Hex(jarInput.getFile().getAbsolutePath()).substring(0, 8);
if (destName.endsWith(".jar")) {
destName = destName.substring(0, destName.length() - 4);
}
/*得到输出文件*/
File dest = outputProvider.getContentLocation(destName + "_" + hexName,
jarInput.getContentTypes(), jarInput.getScopes(), Format.JAR);
if (isIncremental) {
switch (status) {
case NOTCHANGED:
break;
case ADDED:
foreachJar(dest, jarInput);
break;
case CHANGED:
diffJar(dest, jarInput);
break;
case REMOVED:
try {
deleteScan(dest);
if (dest.exists()) {
FileUtils.forceDelete(dest);
}
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
foreachJar(dest, jarInput);
}
}
for (DirectoryInput directoryInput : input.getDirectoryInputs()) {
foreachClass(directoryInput);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
复制代码
我在遍历循环jar,开始的时候咱们先判断当前此次是否是增量编译,若是不是增量则开始遍历全部jar,若是是增量编译,会去获取当前jar的状态,若是状态是删除则先扫描jar以后把output 中的文件删除。若是状态是ADD的状况下,则扫描修改这个jar文件。最后若是是CHANGE状态,则先扫描新久两个jar,比较获取删除的文件,而后重复ADD操做。
spa
private void foreachClass(DirectoryInput directoryInput) throws IOException {
File dest = outputProvider.getContentLocation(directoryInput.getName(), directoryInput.getContentTypes(),
directoryInput.getScopes(), Format.DIRECTORY);
Map<File, Status> map = directoryInput.getChangedFiles();
File dir = directoryInput.getFile();
if (isIncremental) {
for (Map.Entry<File, Status> entry : map.entrySet()) {
Status status = entry.getValue();
File file = entry.getKey();
String destFilePath = file.getAbsolutePath().replace(dir.getAbsolutePath(), dest.getAbsolutePath());
File destFile = new File(destFilePath);
switch (status) {
case NOTCHANGED:
break;
case ADDED:
case CHANGED:
try {
FileUtils.touch(destFile);
} catch (Exception ignored) {
Files.createParentDirs(destFile);
}
modifySingleFile(dir, file, dest);
break;
case REMOVED:
Log.info(entry);
deleteDirectory(destFile, dest);
break;
}
}
} else {
changeFile(dir, dest);
}
}
复制代码
这个是修改.class文件的操做 , 和修改jar包的逻辑基本同样,可是又一个区别,若是是增量编译的状况下,咱们获取的对象是一个Map,而非增量编译的状况下,咱们使用的是整个文件夹路径。
设计
咱们的任务名DoubleTabTransform
这是一次全量编译的耗时
3d