深入理解groovy

静态分派 动态分派

MethodHandle与反射Method区别
Call Site分析
JVM invokedynamic调用指令

元编程:

维基百科 上将元编程描述成一种计算机程序可以将代码看待成数据的能力。

如果能够将代码看做数据,那么代码就可以像数据一样在运行时被修改、更新和替换(你学过编译原理就知道,在 CPU 眼里,程序本来就是数据。先把文本形式的代码变成 Token,再变成 AST,然后是 IR,最后是汇编代码和机器代码。);元编程赋予了编程语言更加强大的表达能力,通过编译期间的展开生成代码或者允许程序在运行时改变自身的行为。归根结底就是一种使用代码生成代码的思想,消灭重复的代码,极大地增强编程语言的表达能力。

运行时和编译时元编程 第一部分

CallSite

invokedynamic 是 Java 7 引入的一条新指令,用以支持动态语言的方法调用。具体来说,它将调用点(CallSite)抽象成一个 Java 类,并且将原本由 Java 虚拟机控制的方法调用以及方法链接暴露给了应用程序。在运行过程中,每一条 invokedynamic 指令将捆绑一个调用点,并且会调用该调用点所链接的方法句柄。

可以动态注入 属性 方法

  1. class Sutdent {
  2. String name
  3. Integer age
  4. def Hellow() {
  5. return "hello"
  6. }
  7. def invokeMethod(String name, Object args) {
  8. println "name:"+name + " args:"+args
  9. }
  10. }


  1. Sutdent.metaClass.sex = "女"
  2. Sutdent.metaClass.set123 = { a, b -> a + b }
  3. def stdent = new Sutdent(name: "xiaoming", age: 12, sex: "nnn")
  4. println(stdent.sex)
  5. println("set123:"+stdent.set123(10,2))

image.png

生命周期

image.png

ext

image.png

  1. apply from: this.file('commom.gradle')

image.png

gradle.properties

image.png

image.png

依赖冲突

image.png

传递依赖

image.png

image.png

外部命令

  1. task('apkcopy') {
  2. doLast {
  3. def sourcePath = this.buildDir.path + '/outputs/apk'
  4. def desActionPath = '/Users/ssy/Desktop/'
  5. def command = "mv -f ${sourcePath} ${desActionPath}"
  6. exec {
  7. try {
  8. executable 'bash'
  9. args '-c', command
  10. println 'the command is execute success'
  11. } catch (GradleException e) {
  12. println 'the command is execute failed'
  13. }
  14. }
  15. }
  16. }

Task执行顺序

  1. task lib2() {
  2. doLast { println 'lib2' }
  3. }
  4. task lib1(dependsOn: lib2) {
  5. doLast {
  6. println 'lib1'
  7. }
  8. }
  1. task lib3 {
  2. doLast { println 'lib3' }
  3. }
  4. task lib2() {
  5. doLast { println 'lib2' }
  6. }
  7. task nlib1() {
  8. dependsOn this.tasks.findAll {
  9. task ->
  10. return task.name.startsWith('lib')
  11. }
  12. doLast {
  13. println 'nlib1'
  14. }
  15. }
  1. task lib3 {
  2. doLast { println 'lib3' }
  3. }
  4. task lib2() {
  5. doLast { println 'lib2' }
  6. }
  7. task nlib1() {
  8. // dependsOn this.tasks.findAll {
  9. // task ->
  10. // return task.name.startsWith('lib')
  11. // }
  12. dependsOn this.tasks.findByName("lib3")
  13. doLast {
  14. println 'nlib1'
  15. }
  16. }

实战

  1. task autoVersionWrite {
  2. File file = new File(this.getProjectDir().absolutePath + "/version.xml")
  3. if (!file.exists()) {
  4. file.createNewFile()
  5. }
  6. def releases = new XmlParser().parse(file)
  7. def canWrite = true
  8. def out = new StringWriter()
  9. def xml = new groovy.xml.MarkupBuilder(out)
  10. xml.releases {
  11. releases.release.each {
  12. release1 ->
  13. if (Integer.parseInt(release1.versionCode.text()) == rootProject.ext.android.versionCode) {
  14. canWrite = false
  15. }
  16. release {
  17. versionCode(release1.versionCode.text())
  18. versionName(release1.versionName.text())
  19. versionInfo(release1.versionInfo.text())
  20. }
  21. }
  22. if (canWrite) {
  23. release {
  24. versionCode(rootProject.ext.android.versionCode)
  25. versionName(rootProject.ext.android.versionName)
  26. versionInfo(rootProject.ext.android.versionInfo)
  27. }
  28. }
  29. }
  30. def xmlString = """<?xml version='1.0' encoding='UTF-8'?>
  31. """;
  32. file.write(xmlString + out.toString());
  33. }
  1. <?xml version='1.0' encoding='UTF-8'?>
  2. <releases>
  3. <release>
  4. <versionCode>10</versionCode>
  5. <versionInfo>app 的第一个版本</versionInfo>
  6. <versionName>1.0</versionName>
  7. </release>
  8. <release>
  9. <versionCode>12</versionCode>
  10. <versionInfo>app 的第二个版本,上线了一些核心功能</versionInfo>
  11. <versionName>1.2</versionName>
  12. </release>
  13. <release>
  14. <versionCode>13</versionCode>
  15. <versionInfo>app 的第三个版本,上线了一些核心功能</versionInfo>
  16. <versionName>1.3</versionName>
  17. </release>
  18. <release>
  19. <versionCode>20</versionCode>
  20. <versionInfo>app 的第二十个版本,这是一个大版本更新</versionInfo>
  21. <versionName>2.0</versionName>
  22. </release>
  23. </releases>

任务的输入输出

image.pngimage.png

挂接自定义Task到构造过程中

https://www.imooc.com/article/68468

image.png

Settings

依赖-管理依赖的版本(传递(transitive)\排除(exclude)\强制(force)\动态版本(+))

https://blog.csdn.net/l419070777/article/details/79473990

SourceSet

image.png

  1. sourceSets {
  2. main {
  3. res.srcDirs = ['src/main/res','src/main/res-ad','src/main/res-player']
  4. // main.res.srcDirs += ['src/main/res-qa', 'src/main/res-wb']
  5. }
  6. }

Plugin 中引用包

  1. @AutoService(VariantProcessor::class)
  2. class ThreadVariantProcessor : VariantProcessor {
  3. override fun process(variant: BaseVariant) {
  4. if (variant !is LibraryVariant) {
  5. var baseVariantData = (variant as ApplicationVariantImpl).variantData
  6. var p = baseVariantData.scope.globalScope.project
  7. p.dependencies.add(
  8. "implementation", "com.ssy.ferry:ferry-android-instrument-thread:1.0.1}"
  9. )
  10. }
  11. }
  12. }