写点什么

深入学习 -Gradle- 自动化构建技术(六)Gradle- 插件平台化框架 -ByteX- 探秘之旅

用户头像
Android架构
关注
发布于: 1 小时前

Map<Boolean, List<Person>> collect1 = persons.stream().collect(Collectors.partitioningBy(person -> person.getScore() >= 60));System.out.println(collect1);


  • 4、统计 aa.txt 里面的单词数:


public static void main(String[] args) throws IOException {InputStream resourceAsStream = Person.class.getClassLoader().getResourceAsStream("aa.txt");BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(resourceAsStream));bufferedReader.lines().flatMap(x->Stream.of(x.split(" "))).sorted().collect(Collectors.groupingBy(String::toString)).forEach((a,b)-> System.out.println(a+":"+b.size()));bufferedReader.close();}

4、复杂泛型

1)、泛型是什么?

泛型,即 「“参数化类型”」。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

2)、泛型的好处

  • 「适用于多种数据类型执行相同的代码」

  • 「泛型中的类型在使用时指定,不需要强制类型转换」

3)、泛型类和泛型接口

泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。而这种参数类型可以用在类、接口和方法中,分别被称为 「泛型类、泛型接口、泛型方法」

泛型类

引入一个类型变量 T(其他大写字母都可以,不过常用的就是 T,E,K,V 等等),并且用<>括起来,并放在类名的后面。「泛型类是允许有多个类型变量的」。常见的示例代码如下所示:


public class NormalGeneric<K> {private K data;


public NormalGeneric() {}


public NormalGeneric(K data) {this.data = data;}


public K getData() {return data;}


public void setData(K data) {this.data = data;}}


public class NormalGeneric2<T,K> {private T data;private K result;


public NormalGeneric2() {}


public NormalGeneric2(T data) {this();this.data = data;}


public NormalGeneric2(T data, K result) {this.data = data;this.result = result;}


public T getData() {return data;}


public void setData(T data) {this.data = data;}


public K getResult() {return result;}


public void setResult(K result) {this.result = result;}}

泛型接口

泛型接口与泛型类的定义基本相同。示例代码如下所示:


public interface Genertor<T> {public T next();}


但是,「实现泛型接口的类,有两种实现方法」

1、未传入泛型实参

在 new 出类的实例时,需要指定具体类型:


public class ImplGenertor<T> implements Genertor<T> {@Overridepublic T next() {return null;}}

2、传入泛型实参

在 new 出类的实例时,和普通的类没区别。


public class ImplGenertor2 implements Genertor<String> {@Overridepublic String next() {return null;}}

泛型方法

泛型方法的 定义在 「修饰符与返回值」 的中间。示例代码如下所示:


public <T> T genericMethod(T...a){return a[a.length/2];}


泛型方法,是在调用方法的时候指明泛型的具体类型,泛型方法可以在任何地方和任何场景中使用,包括普通类


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


和泛型类。

泛型类中定义的普通方法和泛型方法的区别

在普通方法中:


// 虽然在方法中使用了泛型,但是这并不是一个泛型方法。// 这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型。// 所以在这个方法中才可以继续使用 T 这个泛型。public T getKey(){return key;}


在泛型方法中:


/**


  • 这才是一个真正的泛型方法。

  • 首先在 public 与返回值之间的 <T> 必不可少,这表明这是一个泛型方法,并且声明了一个泛型 T

  • 这个 T 可以出现在这个泛型方法的任意位置,泛型的数量也可以为任意多个。*/public <T,K> K showKeyName(Generic<T> container){// ...}

4)、限定类型变量

public class ClassBorder<T extends Comparable> {...}


public class GenericRaw<T extends ArrayList&Comparable> {...}


-<T extends Comparable>「T 表示应该绑定类型的子类型,Comparable 表示绑定类型,子类型和绑定类型可以是类也可以是接口」


  • 「extends 左右都允许有多个,如 T,V extends Comparable&Serializable」

  • 「注意限定类型中,只允许有一个类,而且如果有类,这个类必须是限定列表的第一个」

  • 「限定类型变量既可以用在泛型方法上也可以用在泛型类上」

5)、泛型中的约束和局限性

  • 1、不能用基本类型实例化类型参数。

  • 2、运行时类型查询只适用于原始类型。

  • 3、泛型类的静态上下文中类型变量失效:不能在静态域或方法中引用类型变量。因为泛型是要在对象创建的时候才知道是什么类型的,而对象创建的代码执行先后顺序是 static 的部分,然后才是构造函数等等。所以在对象初始化之前 static 的部分已经执行了,如果你在静态部分引用泛型,那么毫无疑问虚拟机根本不知道是什么东西,因为这个时候类还没有初始化。

  • 4、不能创建参数化类型的数组,但是可以定义参数化类型的数组。

  • 5、不能实例化类型变量。

  • 6、不能使用 try-catch 捕获泛型类的实例。

6)、泛型类型的继承规则

泛型类可以继承或者扩展其他泛型类,比如 List 和 ArrayList:


private static class ExtendPair<T> extends Pair<T>{...}

7)、通配符类型

  • ?extends X「表示类型的上界,类型参数是 X 的子类」

  • ?super X「表示类型的下界,类型参数是 X 的超类」

?extends X

如果其中提供了 get 和 set 类型参数变量的方法的话,set 方法是不允许被调用的,会出现编译错误,而 get 方法则没问题。


?extends X 表示类型的上界,类型参数是 X 的子类,那么可以肯定的说,get 方法返回的一定是个 X(不管是 X 或者 X 的子类)编译器是可以确定知道的。但是 set 方法只知道传入的是个 X,至于具体是 X 的哪个子类,是不知道的。


因此,「?extends X 主要用于安全地访问数据,可以访问 X 及其子类型,并且不能写入非 null 的数据」

?super X

如果其中提供了 get 和 set 类型参数变量的方法的话,set 方法可以被调用,且能传入的参数只能是 X 或者 X 的子类。而 get 方法只会返回一个 Object 类型的值。


? super X 表示类型的下界,类型参数是 X 的超类(包括 X 本身),那么可以肯定的说,get 方法返回的一定是个 X 的超类,那么到底是哪个超类?不知道,但是可以肯定的说,Object 一定是它的超类,所以 get 方法返回 Object。编译器是可以确定知道的。对于 set 方法来说,编译器不知道它需要的确切类型,但是 X 和 X 的子类可以安全的转型为 X。


因此,「?super X 主要用于安全地写入数据,可以写入 X 及其子类型」

无限定的通配符 ?

「表示对类型没有什么限制,可以把 ?看成所有类型的父类,如 ArrayList<?>」

8)、虚拟机是如何实现泛型的?

泛型思想早在 C++ 语言的模板(Template)中就开始生根发芽,「在 Java 语言处于还没有出现泛型的版本时,只能通过 Object 是所有类型的父类和类型强制转换两个特点的配合来实现类型泛化」


由于 Java 语言里面所有的类型都继承于 java.lang.Object,所以 Object 转型成任何对象都是有可能的。但是也因为有无限的可能性,就只有程序员和运行期的虚拟机才知道这个 Object 到底是个什么类型的对象。在编译期间,编译器无法检查这个 Object 的强制转型是否成功,如果仅仅依赖程序员去保障这项操作的正确性,许多 ClassCastException 的风险就会转嫁到程序运行期之中。


此外,泛型技术在 C#/C++ 和 Java 之中的使用方式看似相同,但实现上却有着根本性的分歧,C# 里面的泛型无论在程序源码中、编译后的 IL 中(Intermediate Language,中间语言,这时候泛型是一个占位符),或是运行期的 CLR 中,都是切实存在的,「List<int> 与 List<String> 就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型称为真实泛型」


「Java 语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码」,因此,对于运行期的 Java 语言来说,ArrayList<int> 与 ArrayList<String> 就是同一个类,所以 「泛型技术实际上是 Java 语言的一颗语法糖,Java 语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型」。 将一段 Java 代码编译成 Class 文件,然后再用字节码反编译工具进行反编译后,将会发现泛型都不见了,程序又变回了 Java 泛型出现之前的写法,泛型类型都变回了原生类型。


由于 Java 泛型的引入,各种场景(虚拟机解析、反射等)下的方法调用都可能对原有的基础产生影响和新的需求,如在泛型类中如何获取传入的参数化类型等。因此,JCP 组织对虚拟机规范做出了相应的修改,引入了诸如 Signature、LocalVariableTypeTable 等新的属性用于解决伴随泛型而来的参数类型的识别问题,「Signature 是其中最重要的一项属性,它的作用就是存储一个方法在字节码层面的特征签名,这个属性中保存的参数类型并不是原生类型,而是包括了参数化类型的信息」。修改后的虚拟机规范要求所有能识别 49.0 以上版本的 Class 文件的虚拟机都要能正确地识别 Signature 参数。


最后,「从 Signature 属性的出现我们还可以得出结论,擦除法所谓的擦除,仅仅是对方法的 Code 属性中的字节码进行擦除,实际上元数据中还是保留了泛型信息,这也是我们能通过反射手段取得参数化类型的根本依据」

二、初识 ByteX

ByteX 使用了纯 Java 来编写源码,它是一个基于 Gradle transform api 和 ASM 的字节码插桩平台。


?

调试:gradle clean :example:assembleRelease -Dorg.gradle.debug=true --no-daemon

?

1、优势

  • 1)、「自动集成到其它宿主和插件一起整合为一个单独的 MainTransformFlow,结合 class 文件多线程并发处理,避免了打包的额外时间呈线性增长」

  • 2)、「插件、宿主之间完全解耦,便于协同开发」

  • 3)、「common module 提供通用的代码复用,每个插件只需专注自身的字节码插桩逻辑」

2、MainTransformFlow 基本流程

在 MainTransformFlow implements MainProcessHandler 常规处理过程,会遍历两次工程构建中的所有 class。


  • 1)、第一次,遍历 traverse 与 traverseAndroidJar 过程,以形成完整的类图。

  • 2)、第二次,执行 transform:再遍历一次工程中所有的构建产物,并对 class 文件做处理后输出。

3、如何自定义独立的 TransformFlow?

重写 IPlugin 的 provideTransformFlow 即可。

4、类图对象

context.getClassGraph() 获取类图对象,两个 TransformFlow 的类图是隔离的。

5、MainProcessHandler

  • 通过复写 process 方法,注册自己的 FlieProcessor 来处理。

  • FileProcessor 采用了责任链模式,每个 class 文件都会流经一系列的 FileProcessor 来处理。

6、IPlugin.hookTransformName()

「使用 反射 Hook 方式 将 Transform 注册到 proguard 之后」

三、ByteX 插件平台构建流程探秘

添加 apply plugin: 'bytex' 之后,bytex 可以在 Gradle 的构建流程中起作用了。这里的插件 id 为 bytex,我们找到 bytex.properties 文件,查看里面映射的实现类,如下所示:


implementation-class=com.ss.android.ugc.bytex.base.ByteXPlugin


可以看到,bytex 的实现类为 ByteXPlugin,其源码如下所示:


public class ByteXPlugin implements Plugin<Project> {@Overridepublic void apply(@NotNull Project project) {// 1AppExtension android = project.getExtensions().getByType(AppExtension.class);// 2ByteXExtension extension = project.getExtensions().create("ByteX", ByteXExtension.class);// 3android.registerTransform(new ByteXTransform(new Context(project, android, extension)));}}


首先,注释 1 处,获取 Android 为 App 提供的扩展属性 AppExtension 实例。然后,在注释 2 处,获取 ByteX 自身创建的扩展属性 ByteXExtension 实例。最后,在注释 3 处,注册 ByteXTransform 实例。ByteXTransform 继承了抽象类 CommonTransform,其实现了关键的 transform 方法,其实现源码如下所示:


@Overridepublic final void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {super.transform(transformInvocation);// 1、如果不是增量模式,则清楚输出目录的文件。if (!transformInvocation.isIncremental()) {transformInvocation.getOutputProvider().deleteAll();}// 2、获取 transformContext 实例。TransformContext transformContext = getTransformContext(transformInvocation);// 3、初始化 HtmlReporter(生成 ByteX 构建产生日志的 HTML 文件)init(transformContext);// 4、过滤掉没有打开插件开关的 plugin。List<IPlugin> plugins = getPlugins().stream().filter(p -> p.enable(transformContext)).collect(Collectors.toList());Timer timer = new Timer();// 5、创建一个 transformEngine 实例。TransformEngine transformEngine = new TransformEngine(transformContext);try {if (!plugins.isEmpty()) {// 6、使用 PriorityQueue 对每一个 TransformFlow 进行优先级排序(在这里添加的是与之对应的实现类 MainTransformFlow)。Queue<TransformFlow> flowSet = new PriorityQueue<>((o1, o2) -> o2.getPriority() - o1.getPriority());MainTransformFlow commonFlow = new MainTransformFlow(transformEngine);flowSet.add(commonFlow);for (int i = 0; i < plugins.size(); i++) {// 7、给每一个 Plugin 注册 MainTransformFlow,其实质是将每一个 Plugin 的 MainProcessHandler 添加到 MainTransformFlow 中的 handlers 列表中。IPlugin plugin = plugins.get(i);TransformFlow flow = plugin.registerTransformFlow(commonFlow, transformContext);if (!flowSet.contains(flow)) {flowSet.add(flow);}}while (!flowSet.isEmpty()) {TransformFlow flow = flowSet.poll();if (flow != null) {if (flowSet.size() == 0) {flow.asTail();}// 8、按指定优先级执行每一个 TransformFlow 的 run 方法,默认只有一个 MainTransformFlow 实例。flow.run();// 9、获取流中的 graph 类图对象并清除。Graph graph = flow.getClassGraph();if (graph != null) {//clear the class diagram.we won’t use it anymoregraph.clear();}}}} else {transformEngine.skip();}// 10afterTransform(transformInvocation);} catch (Throwable throwable) {LevelLog.sDefaultLogger.e(throwable.getClass().getName(), throwable);throw throwable;} finally {for (IPlugin plugin : plugins) {try {plugin.afterExecute();} catch (Throwable throwable) {LevelLog.sDefaultLogger.e("do afterExecute", throwable);}}transformContext.release();release();timer.record("Total cost time = [%s ms]");if (BooleanProperty.ENABLE_HTML_LOG.value()) {HtmlReporter.getInstance().createHtmlReporter(getName());HtmlReporter.getInstance().reset();}}}


在注释 7 处,调用了 plugin.registerTransformFlow 方法,其源码如下所示:


@Nonnull@Overridepublic final TransformFlow registerTransformFlow(@Nonnull MainTransformFlow mainFlow, @Nonnull TransformContext transformContext) {if (transformFlow == null) {transformFlow = provideTransformFlow(mainFlow, transformContext);if (transformFlow == null) {throw new RuntimeException("TransformFlow can not be null.");}}return transformFlow;}


这里继续调用了 provideTransformFlow 方法,其源码如下所示:


/**


  • create a new transformFlow or just return mainFlow and append a handler.

  • It will be called by {@link IPlugin#registerTransformFlow(MainTransformFlow, TransformContext)} when

  • handle start.

  • @param mainFlow main TransformFlow

  • @param transformContext handle context

  • @return return a new TransformFlow object if you want make a new flow for current plugin*/protected TransformFlow provideTransformFlow(@Nonnull MainTransformFlow mainFlow, @Nonnull TransformContext transformContext) {return mainFlow.appendHandler(this);}


可以看到,通过调用 mainFlow.appendHandler(this) 方法将每一个 Plugin 的 MainProcessHandler 添加到 MainTransformFlow 中的 handlers 列表之中。


在注释 8 处,按指定优先级执行了每一个 TransformFlow 的 run 方法,默认只有一个 MainTransformFlow 实例。我们看到了 MianTransformFlow 的 run 方法:


@Overridepublic void run() throws IOException, InterruptedException {try {// 1beginRun();// 2runTransform();} finally {// 3endRun();}}


首先,在注释 1 出,调用了 beginRun 方法,其实现如下:


// AbsTransformFlowprotected void beginRun() {transformEngine.beginRun();}


// TransformEnginepublic void beginRun(){context.markRunningState(false);}


// TransformContextprivate final AtomicBoolean running = new AtomicBoolean(false);


void markRunningState(boolean running) {this.running.set(running);}


最后,在 TransformContext 实例中使用了一个 AtomicBoolean 实例标记 MainTransformFlow 是否正在运行中。


然后,在注释 2 处执行了 runTransform 方法,这里就是真正执行 transform 的地方,其源码如下所示:


private void runTransform() throws IOException, InterruptedException {if (handlers.isEmpty()) return;Timer timer = new Timer();timer.startRecord("PRE_PROCESS");timer.startRecord("INIT");// 1、初始化 handlers 列表中的每一个 handler。for (MainProcessHandler handler : handlers) {handler.init(transformEngine);}timer.stopRecord("INIT", "Process init cost time = [%s ms]");// 如果不是 跳过 traverse 仅仅只执行 Transform 方法时,才执行 traverse 过程。if (!isOnePassEnough()) {if (!handlers.isEmpty() && context.isIncremental()) {timer.startRecord("TRAVERSE_INCREMENTAL");// 2、如果是 增量模式,则执行 traverseArtifactOnly(仅仅增量遍历产物)调用每一个 plugin 的对应的 MainProcessHandler 的 traverseIncremental 方法。这里最终会调用 ClassFileAnalyzer.handle 方法进行遍历分发操作。traverseArtifactOnly(getProcessors(Process.TRAVERSE_INCREMENTAL, new ClassFileAnalyzer(context, Process.TRAVERSE_INCREMENTAL, null, handlers)));timer.stopRecord("TRAVERSE_INCREMENTAL", "Process project all .class files cost time = [%s ms]");}handlers.forEach(plugin -> plugin.beforeTraverse(transformEngine));timer.startRecord("LOADCACHE");// 3、创建一个 CachedGraphBuilder 对象:能够缓存 类图 的 类图构建者对象。GraphBuilder graphBuilder = new CachedGraphBuilder(context.getGraphCache(), context.isIncremental(), context.shouldSaveCache());if (context.isIncremental() && !graphBuilder.isCacheValid()) {// 4、如果是增量更新 && graphBuilder 的缓存失效则直接请求非增量运行。context.requestNotIncremental();}timer.stopRecord("LOADCACHE", "Process loading cache cost time = [%s ms]");// 5、内部会调用 running.set(true) 来标记正在运行的状态。running();if (!handlers.isEmpty()) {timer.startRecord("PROJECT_CLASS");// 6、执行 traverseArtifactOnly(遍历产物)调用每一个 plugin 的对应的 MainProcessHandler 的 traverse 方法,这里最终会调用 ClassFileAnalyzer.handle 方法进行遍历分发操作。traverseArtifactOnly(getProcessors(Process.TRAVERSE, new ClassFileAnalyzer(context, Process.TRAVERSE, graphBuilder, handlers)));timer.stopRecord("PROJECT_CLASS", "Process project all .class files cost time = [%s ms]");}if (!handlers.isEmpty()) {timer.startRecord("ANDROID");// 7、仅仅遍历 Android.jartraverseAndroidJarOnly(getProcessors(Process.TRAVERSE_ANDROID, new ClassFileAnalyzer(context, Process.TRAVERSE_ANDROID, graphBuilder, handlers)));timer.stopRecord("ANDROID", "Process android jar cost time = [%s ms]");}timer.startRecord("SAVECACHE");// 8、构建 mClassGraph 类图实例。mClassGraph = graphBuilder.build();timer.stopRecord("SAVECACHE", "Process saving cache cost time = [%s ms]");}timer.stopRecord("PRE_PROCESS", "Collect info cost time = [%s ms]");if (!handlers.isEmpty()) {timer.startRecord("PROCESS");// 9、遍历执行每一个 plugin 的 transform 方法。transform(getProcessors(Process.TRANSFORM, new ClassFileTransformer(handlers, needPreVerify(), needVerify())));timer.stopRecord("PROCESS", "Transform cost time = [%s ms]");}}


首先,在注释 1 处,遍历调用了每一个 MainProcessHandler 的 init 方法,它是用于 transform 开始前的初始化实现方法。


MainProcessHandler 接口的 init 方法是一个 default 方法,里面直接调用了每一个 pluign 实现的 init 方法(如果 plugin 没有实现,则仅仅调用 CommonPlugin 的实现的 init 方法:这里通常是用于把不需要处理的文件添加到 mWhiteList 列表),这里可以做一些 plugin 的准备工作。

1、仅仅遍历产物

traverseArtifactOnly(getProcessors(Process.TRAVERSE, new ClassFileAnalyzer(context, Process.TRAVERSE, graphBuilder, handlers)));


getProcessors 方法的源码如下所示:


private FileProcessor[] getProcessors(Process process, FileHandler fileHandler) {List<FileProcessor> processors = handlers.stream().flatMap((Function<MainProcessHandler, Stream<FileProcessor>>) handler -> handler.process(process).stream()).collect(Collectors.toList());switch (process) {case TRAVERSE_INCREMENTAL:processors.add(0, new FilterFileProcessor(fileData -> fileData.getStatus() != Status.NOTCHANGED));processors.add(new IncrementalFileProcessor(handlers, ClassFileProcessor.newInstance(fileHandler)));break;case TRAVERSE:case TRAVERSE_ANDROID:case TRANSFORM:processors.add(ClassFileProcessor.newInstance(fileHandler));processors.add(0, new FilterFileProcessor(fileData -> fileData.getStatus() != Status.NOTCHANGED && fileData.getStatus() != Status.REMOVED))break;default:throw new RuntimeException("Unknow Process:" + process);}return processors.toArray(new FileProcessor[0]);}


这里的 processor 的添加由 增量 进行界定,具体的处理标准如下:


  • TRAVERSE_INCREMENTAL

  • FilterFileProcessor「按照不同的过程过滤掉不需要的 FileData」

  • IncrementalFileProcessor「用于进行 增量文件的处理」

  • TRAVERSE/TRAVERSE_ANDROID/TRANSFORM:

  • FilterFileProcessor「按照不同的过程过滤掉不需要的 FileData」

  • ClassFileProcessor「用于处理 .class 文件」

2、仅仅遍历 Android Jar 包

traverseAndroidJarOnly(getProcessors(Process.TRAVERSE_ANDROID, new ClassFileAnalyzer(context, Process.TRAVERSE_ANDROID, graphBuilder, handlers)));

3、构建 mClassGraph 类图对象

mClassGraph = graphBuilder.build();

4、执行 Transform

transform(getProcessors(Process.TRANSFORM, new ClassFileTransformer(handlers, needPreVerify(), needVerify())));


transform 的源码如下所示:


// AbsTransformFlow 类中 protected AbsTransformFlow transform(FileProcessor... processors) throws IOException, InterruptedException {beforeTransform(transformEngine);transformEngine.transform(isLast, processors);afterTransform(transformEngine);return this;}

1)、beforeTransform(transformEngine)

// MainTransformFlow@Overrideprotected AbsTransformFlow beforeTransform(TransformEngine transformEngine) {// 1handlers.forEach(plugin -> plugin.beforeTransform(transformEngine));return this;}


注释 1 处,遍历执行 每一个 plugin 的 beforeTransform 方法做一些自身 transform 前的准备工作。

2)、transformEngine.transform(isLast, processors)

// TranformEnginepublic void transform(boolean isLast, FileProcessor... processors) {Schedulers.FORKJOINPOOL().invoke(new PerformTransformTask(context.allFiles(), getProcessorList(processors), isLast, context));}


Shedulers.FORKJOINPOOL() 方法的源码如下所示:


public class Schedulers {private static final int cpuCount = Runtime.getRuntime().availableProcessors();private final static ExecutorService IO = new ThreadPoolExecutor(0, cpuCount * 3,30L, TimeUnit.SECONDS,new LinkedBlockingQueue<>());


// 1private static final ExecutorService COMPUTATION = Executors.newWorkStealingPool(cpuCount);


public static Worker IO() {return new Worker(IO);}


public static Worker COMPUTATION() {return new Worker(COMPUTATION);}


public static ForkJoinPool FORKJOINPOOL() {return (ForkJoinPool) COMPUTATION;}}


可以看到,最终是执行 Executors.newWorkStealingPool(cpuCount) 方法生成了一个 ForkJoinPool 实例。


ForkJoinPool 与 ThreadPoolExecutor 是属于平级关系,ForkJoinPool 线程池是为了实现“分治法”这一思想而创建的,通过把大任务拆分成小任务,然后再把小任务的结果汇总起来就是最终的结果,和 MapReduce 的思想很类似。除了“分治法”之外,ForkJoinPool 还使用了工作窃取算法,即所有线程均尝试找到并执行已提交的任务,或是通过其他任务创建的子任务。有了它我们就可以尽量避免一个线程执行完自己的任务后“无所事事”的情况。


然后这里会回调 PerformTransformTask 实例的 compute 方法,源码如下所示:


@Overrideprotected void compute() {if (outputFile) {// 1、如果是最后一个 TransformFlow,则递归调用所有的 FileTransformTask。List<FileTransformTask> tasks = source.map(cache -> new FileTransformTask(context, cache, processors)).collect(Collectors.toList());// 2、对于 Fork/Join 模式,假如 Pool 里面线程数量是固定的,那么调用子任务的 fork 方法相当于 A 先分工给 B,然后 A 当监工不干活,B 去完成 A 交代的任务。所以上面的模式相当于浪费了一个线程。那么如果使用 invokeAll 相当于 A 分工给 B 后,A 和 B 都去完成工作。这样可以更好的利用线程池,缩短执行的时间。invokeAll(tasks);} else {// 3、、递归调用 FileTransformTaskPerformTraverseTask traverseTask = new PerformTraverseTask(source, processors);invokeAll(traverseTask);}}


在注释 1 处,如果是最后一个 TransformFlow,则调用所有的 FileTransformTask。注释 2 处,对于 Fork/Join 模式,假如 Pool 里面线程数量是固定的,那么调用子任务的 fork 方法相当于 A 先分工给 B,然后 A 当监工不干活,B 去完成 A 交代的任务。所以上面的模式相当于浪费了一个线程。那么如果使用 invokeAll 相当于 A 分工给 B 后,A 和 B 都去完成工作。这样可以更好的利用线程池,缩短执行的时间。注释 3 处,执行了 ForkJoinTask 的 invokeAll 方法,这里便会回调 compute 方法,源码如下所示:


@Overrideprotected void compute() {List<FileTraverseTask> tasks = source.map(cache -> new FileTraverseTask(cache, processors)).collect(Collectors.toList());// 1invokeAll(tasks);}


注释 1 处,继续回调所有的 FileTraverseTask 实例的 compute 方法,源码如下所示:


@Overrideprotected void compute() {List<TraverseTask> tasks = fileCache.stream().map(file -> new TraverseTask(fileCache, file, processors)).toList().blockingGet();// 1invokeAll(tasks);}


注释 1 处,继续回调所有的 TraverseTask 实例的 compute 方法,源码如下所示:


@Overrideprotected void compute() {try {Input input = new Input(fileCache.getContent(), file);ProcessorChain chain = new ProcessorChain(processors, input, 0);// 1、调用 ProcessorChain 的 proceed 方法。chain.proceed(input);} catch (IOException e) {throw new RuntimeException(e);}}


注释 1 处,调用了 ProcessorChain 的 proceed 方法。源码如下所示:


@Overridepublic Output proceed(Input input) throws IOException {if (index >= processors.size()) throw new AssertionError();// 1FileProcessor next = processors.get(index);


return next.process(new ProcessorChain(processors, input, index + 1));}


注释 1 处,会从 processors 处理器列表中获取第一个处理器—FilterFileProcessor,并调用它的 process 方法,源码如下所示:


@Overridepublic Output process(Chain chain) throws IOException {Input input = chain.input();if (predicate.test(input.getFileData())) {// 1return chain.proceed(input);} else {return new Output(input.getFileData());}}


注释 1 处,如果有 FileData 的话,则继续调用 chain 的 proceed 方法,内部会继续调用 ClassFileProcessor 的 process 方法,源码如下:


@Overridepublic Output process(Chain chain) throws IOException {Input input = chain.input();FileData fileData = input.getFileData();if (fileData.getRelativePath().endsWith(".class")) {// 1、如果 fileData 是 .class 文件,则调用 ClassFileTransformer 的 handle 方法进行处理。handler.handle(fileData);}// 2、return chain.proceed(input);}


注释 1 处,如果 fileData 是 .class 文件,则调用 ClassFileTransformer 的 handle 方法进行处理。其源码如下所示:


@Overridepublic void handle(FileData fileData) {try {byte[] raw = fileData.getBytes();String relativePath = fileData.getRelativePath();int cwFlags = 0; //compute nothingint crFlags = 0;for (MainProcessHandler handler : handlers) {// 1、设置 ClassWrite 的 flag 的默认值为 ClassWriter.COMPUTE_MAXS。cwFlags |= handler.flagForClassWriter();if ((handler.flagForClassReader(Process.TRANSFORM) & ClassReader.EXPAND_FRAMES) == ClassReader.EXPAND_FRAMES) {crFlags |= ClassReader.EXPAND_FRAMES;}}ClassReader cr = new ClassReader(raw);ClassWriter cw = new ClassWriter(cwFlags);ClassVisitorChain chain = getClassVisitorChain(relativePath);if (needPreVerify) {// 2、如果需要预校验,则将责任链表头尾部设置为 AsmVerifyClassVisitor 实例。chain.connect(new AsmVerifyClassVisitor());}if (handlers != null && !handlers.isEmpty()) {for (MainProcessHandler handler : handlers) {// 3、遍历执行所有 plugin 的 transform。其内部会使用 chain.connect(new ReferCheckClassVisitor(context)) 的方式 将 if (!handler.transform(relativePath, chain)) {fileData.delete();return;}}}// 4、兼容 ClassNode 处理的模式

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
深入学习-Gradle-自动化构建技术(六)Gradle-插件平台化框架-ByteX-探秘之旅