我的编程空间,编程开发者的网络收藏夹
学习永远不晚

ProtoBuf动态拆分Gradle Module源码分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

ProtoBuf动态拆分Gradle Module源码分析

本文小编为大家详细介绍“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: v1name: buf.xxx.co/xxx/xxxxxxdeps:  - buf.xxxxx.co/google/protobufbuild:  excludes:    - settingbreaking:  use:    - FILElint:  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("class="lazy" data-src/main/proto")    main.proto.class="lazy" data-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文件拷贝到这个壳工程的class="lazy" data-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源码分析”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

ProtoBuf动态拆分Gradle Module源码分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

ProtoBuf动态拆分Gradle Module源码分析

本文小编为大家详细介绍“ProtoBuf动态拆分Gradle Module源码分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“ProtoBuf动态拆分Gradle Module源码分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入
2023-07-05

ProtoBuf动态拆分Gradle Module解析

这篇文章主要为大家介绍了ProtoBuf动态拆分Gradle Module解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-27

Java的自动装箱和拆箱源码分析

这篇“Java的自动装箱和拆箱源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java的自动装箱和拆箱源码分析”文章吧
2023-06-30

Webpack学习之动态import原理及源码分析

这篇文章主要为大家介绍了Webpack学习之动态import原理及源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-17

Linux JSP动态代码分析

在 Linux 系统上,JSP(JavaServer Pages)动态代码分析通常涉及检查 JSP 文件中的 Java 代码、标签库、表达式等,以确保代码质量和性能使用文本编辑器或集成开发环境(IDE):在 Linux 上,有许多文本编辑器
Linux JSP动态代码分析
2024-09-21

ContentProvider启动流程源码分析

本文小编为大家详细介绍“ContentProvider启动流程源码分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“ContentProvider启动流程源码分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。C
2023-07-05

SpringBoot启动流程SpringApplication源码分析

这篇“SpringBoot启动流程SpringApplication源码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“S
2023-07-05

spring自动注入AutowiredAnnotationBeanPostProcessor源码分析

本篇内容介绍了“spring自动注入AutowiredAnnotationBeanPostProcessor源码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔
2023-07-05

Android动画(四)动画框架源码分析

本篇难度较大,慎入 也许可以先去看总结在来一起分析 从我们写的开始进入:fun click(view: View) {val textView = findViewById(R.id.tv)val animator = ObjectAnim
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录