中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ProtoBuf動態拆分Gradle?Module源碼分析

發布時間:2023-02-27 16:50:53 來源:億速云 閱讀:138 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“ProtoBuf動態拆分Gradle Module源碼分析”,內容詳細,步驟清晰,細節處理妥當,希望這篇“ProtoBuf動態拆分Gradle Module源碼分析”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

預期

當前安卓的所有proto都生成在一個module中,但是其實業務同學需要的并不是一個大雜燴, 只需要其中他們所關心的proto生成的類則足以。所以我們希望能將這樣一個大雜燴的倉庫打散,拆解成多個module

ProtoBuf動態拆分Gradle?Module源碼分析

buf.yaml

Protobuf是Protocol Buffers的簡稱,它是Google公司開發的一種數據描述語言,用于描述一種輕便高效的結構化數據存儲格式,并于2008年對外開源。Protobuf可以用于結構化數據串行化,或者說序列化。它的設計非常適用于在網絡通訊中的數據載體,很適合做數據存儲或 RPC 數據交換格式,它序列化出來的數據量少再加上以 K-V 的方式來存儲數據,對消息的版本兼容性非常強,可用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。開發者可以通過Protobuf附帶的工具生成代碼并實現將結構化數據序列化的功能。

在我司proto相關的都是由后端大佬們來維護的,然后這個協議倉庫會被android/ios/后端/前端 依賴之后生成對應的代碼,然后直接使用。

而proto文件中允許導入對于其他proto文件的依賴,所以這就導致了想要把幾個proto轉化成一個java-library工程,還需要考慮依賴問題。所以由 我們的后端來定義了一個buf.yaml的數據格式。

version: v1
name: buf.xxx.co/xxx/xxxxxx
deps:
  - buf.xxxxx.co/google/protobuf
build:
  excludes:
    - setting
breaking:
  use:
    - FILE
lint:
  use:
    - DEFAULT

name代表了這個工程的名字,deps則表示了他依賴的proto的工程名。基于這份yaml內容,我們就可以大概確定一個proto工程編譯需要的基礎條件。然后我們只需要一個工具或者插件來幫助我們生成對應的工程就夠了。

模板工程

現在我們基本已經有了一個單一的proto工程的輸入模型了,工程名依賴的工程還有對應文件夾下的proto文件。然后我們就可以基于這部分輸入的模型,生成出第一個模板工程。

plugins {
    id 'java-library'
    id 'org.jetbrains.kotlin.jvm'
    id 'com.google.protobuf'
}


java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

sourceSets {
    def dirs = new ArrayList<String>()
    dirs.add("src/main/proto")
    main.proto.srcDirs = dirs
}

protobuf {
    protoc {
        if (System.getProperty("os.arch").compareTo("aarch74") == 0) {
            artifact = "com.google.protobuf:protoc:$version_protobuf_protoc:osx-x86_64"
        } else {
            artifact = "com.google.protobuf:protoc:$version_protobuf_protoc"
        }
    }
    plugins {
        grpc {
            if (System.getProperty("os.arch").compareTo("aarch74") == 0) {
                artifact = 'io.grpc:protoc-gen-grpc-java:1.36.1:osx-x86_64'
            } else {
                artifact = 'io.grpc:protoc-gen-grpc-java:1.36.1'
            }
        }
    }
    generateProtoTasks {
        all().each { task ->
            task.generateDescriptorSet = true
            task.builtins {
                // In most cases you don't need the full Java output
                // if you use the lite output.
                java {

                }

            }
            task.plugins {
                grpc { option 'lite' }
            }
        }
    }
}
afterEvaluate {
    project.tasks.findByName("compileJava").dependsOn(tasks.findByName("generateProto"))
    project.tasks.findByName("compileKotlin").dependsOn(tasks.findByName("generateProto"))
}
dependencies {
    implementation "org.glassfish:javax.annotation:10.0-b28"
    def grpcJava = '1.36.1'
    compileOnly "io.grpc:grpc-protobuf-lite:${grpcJava}"
    compileOnly "io.grpc:grpc-stub:${grpcJava}"
    compileOnly "io.grpc:grpc-core:${grpcJava}"
    File file = new File(projectDir, "depend.txt")
    if (!file.exists()) {
        return
    }
    def lines = file.readLines()
    if (lines.isEmpty()) {
        return
    }
    lines.forEach {
        logger.lifecycle("project:" + name + "   implementation: " + it)
        implementation(it)
    }
}

如果需要將proto編譯成java代碼,就需要依賴于com.google.protobuf插件,依賴于上面的build.gradle基本就可以將一個proto輸入編譯成一個jar工程。

另外我們需要把所有的proto文件拷貝到這個殼工程的src/main/proto文件夾下,最后我們會將buf.yaml中的name: buf.xxx.co/xxx/xxxxxx/xxx/xxxxxx轉化成工程名,去除掉一些無法識別的字符。

我們生成的模板工程如下:

ProtoBuf動態拆分Gradle?Module源碼分析

其中proto.version會記錄proto內的gitsha值還有文件的lastModified時間,如果輸入發生變更則會重新進行一次文件拷貝操作,避免重復覆蓋的風險。

input.txt則包含了所有proto文件路徑,方便我們進行開發調試。

deps 轉化

由于proto之間存在依賴,沒有依賴則會導致無法將proto轉化成java。所以這里我講buf.yaml中讀取出的deps轉化成了一個depend.txt.

com.xxxx.api:google-protobuf:7.7.7

depend.txt內會逐行寫入當前模塊的依賴,我們會對name進行一次轉化,變成一個可讀的gradle工程名。其中7.7.7的版本只是一個缺省而已,并沒有實際的價值。

多線程操作

這里我們出現了一點點的性能問題, 如果可以gradle插件中盡量多使用點多線程,尤其是這種需要io的操作中。

這里我通過ForkJoinPool,這個是ExecutorService的實現類。其中submit方法中會返回一個ForkJoinTask,我們可以將獲取gitsha值和lastModified放在這個中。之后把所有的ForkJoinTask放到一個數組中。

fun await() {
     forkJoins.forEach {
         it.join()
     }
 }

然后最后暴露一個await方法,來做到所有的獲取方法完成之后再繼續向下執行。

另外則就是殼module的生成,我們也放在了子線程內執行。我們這次使用了線程池的invokeAll方法。

protoFileWalk.hashMap.forEach { (_, pbBufYaml) ->
           callables.add(Callable<Void> {
               val root = FileUtils.getRootProjectDir(settings.gradle)
               try {
                   val file = pbBufYaml.copyLib(File(root, "bapi"))
                   projects[pbBufYaml.projectName()] = file.absolutePath ?: ""
               } catch (e: Exception) {
                   e.printStackTrace()
                   e.message.log()
               }
               null
           })
       }
       executor.invokeAll(callables)

這里有個面試經常出現的考點,多線程操作Hashmap,之后我在測試環節隨機出現了生成工程和include不匹配的問題。所以最后我更換了ConcurrentHashMap就沒有出現這個問題了。

加載殼Module

這部分就和源碼編譯插件基本是一樣的寫法。

projects.forEach { (s, file) ->
              settings.include(":${s}")
              settings.project(":${s}").projectDir = File(file)
          }

把工程插入settings 即可。

讀到這里,這篇“ProtoBuf動態拆分Gradle Module源碼分析”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

兴仁县| 公主岭市| 高淳县| 金平| 邯郸县| 鸡西市| 安福县| 海盐县| 尼木县| 广宁县| 大庆市| 栾城县| 大埔县| 军事| 鲁山县| 花莲市| 金华市| 漯河市| 镇巴县| 友谊县| 宣城市| 江阴市| 溧水县| 惠安县| 泊头市| 嘉定区| 大田县| 靖宇县| 长阳| 五大连池市| 右玉县| 离岛区| 上林县| 开封市| 兰西县| 托克托县| 报价| 耒阳市| 汤原县| 盐亭县| 长丰县|