开源之夏经验分享|Koupleless 社区魏照华:开源精神是场永不停歇的接力

简介: 魏照华是 University of Wollogong 计算机科学专业研究生,开源之夏 2024 Koupleless 社区贡献者。他参与开发了 Koupleless 模块打包插件的 Gradle 版本,旨在为 Gradle 用户提供与 SOFAArk 兼容的模块化研发框架支持。

魏照华

Computer Science
Koupleless 社区贡献者

就读于 University of Wolloging,Computer Science 专业研究生。

本文 5428 字,预计阅读 14 分钟

今天 SOFAStack 邀请到了开源之夏 2024 Koupleless 社区的中选学生魏照华同学!在本项目中,他参与完成了 ​Koupleless 模块打包插件 Gradle 版本​。希望他分享的这段经历,能让更多人了解到 Koupleless 开源社区,感受开源的魅力~

项目链接​:https://summer-ospp.ac.cn/org/prodetail/2495a0374?lang=zh&list=pro

项目信息

项目名称​:Koupleless 模块打包插件 Gradle 版本

项目导师​:梁栎鹏

项目背景​:

在 Koupleless 模块化研发框架里,模块是普通 SpringBoot 或者 Java 代码工程,通过使用 SOFAArk 模块打包插件构建出 jar 包,这个 jar 包就是我们的模块构建产物,通过在一个基座 JVM 里部署多个这样的模块 jar 包,运行起来的时候,​1 个模块 = 1 个 ClassLoader + 1 个 SpringContext​,通过多 ClassLoader 和 SpringContext 的隔离和共享来为模块开发提供最极致的研发效能和资源效能。

而 SOFAArk 打包插件就是将传统 Maven 工程打包成 SOFAArk 模块 jar 包的插件,并且支持设置类的隔离与共享的配置能力(对象的隔离与共享不在该插件里配置)。但是当前 SOFAArk 打包插件只支持 Maven 版本,不支持 Gradle 版本,导致很多 Gradle 的用户无法使用 SOFAArk 来享受到 Koupleless 模块化研发框架的收益。

项目实现思路

SOFAArk 目前拥有两种打包插件,分别为 sofa-ark-maven-plugin 和 sofa-ark-plugin-maven-plugin。前者负责将普通的 Java 工程或者 SpringBoot 工程打包成标准格式的 Ark 包或者 Ark Biz 包,后者是将一个或者多个普通的 jar 包打包成标准格式的 Ark Plugin。这三类 jar 包都有自己特定的格式和内容。具体的内容可以参考如下:

这三类包从包含类别上而言,Ark 包是包含种类最多的包,除了 MANIFEST.MF 文件之外,还包含了业务的 Ark Biz 包、Ark 容器,以及启动相关的内容。Ark 包的 Maven 打包过程,在 SOFAArk 的官方文档^​[1]​^中,已经有了详细的解析。

从这份文档中可以了解到,通过自定义 Maven 插件,按照 SOFAArk 中所定义的格式,重新编排后的 jar 包,就是我们想要得到的目标产物。

回到 Gradle 打包插件上,通过了解 Maven 插件打包的具体实现过程,使用 Gradle 提供的插件 API,来实现上述过程即可。为此,需要去了解 Gradle 的生命周期,依赖管理,自定义插件等内容,进行后续开发工作。

总览整个项目,实现过程中主要处理如下内容:

  • 用户的配置项
  • 项目依赖项
  • 启动类和容器类
  • 插件调试

用户配置项

SOFAArk 打包插件提供了非常丰富的用户配置选项,通过设置这些配置选项,能够打包出满足不同需求的产物内容。不同的配置项会对应不同的特性,这些特性极大地增强了项目构建的灵活性与定制性。并且使得用户能够根据项目实际的运行环境、性能需求以及部署要求等因素,精细地调整打包产物的内容与形式。

Gradle 提供了 extensions 来让插件实现可配置,这一机制提供了一种优雅且强大的方式来定制插件行为。通过自定义 extension 类或者接口,声明需要的配置属性,便可以在插件中使用配置项。

//定义extensions
abstract public class ArkExtension {
   abstract public Property<Boolean> getAttach();
    // 定义一个字符串集合类型的属性excludes,用于指定需要在打包过程中排除的依赖
   abstract public SetProperty<String> getExcludes();
}
//在插件中使用
class ArkPlugin implements Plugin<Project> {
    void apply(Porject project){
      ArkExtension arkExtension = project.getExtensions().create("arkPlugin", ArkPluginExArkExtension.class);
 }
}

这里需要注意的是,使用 extensions 的扩展方式,如果对插件的属性设置了默认值,那么在配置结束阶段,是没有办法获取到用户的自定义配置的。这里考虑到我们需要对 sofa-ark-all 包进行配置,装载进入 runtimeClasspath,以便再后续进行处理。可以通过设置 <span>afterEvaluate</span> 来解决这个问题。<span>afterEvaluate</span> 是 Gradle 提供的一个非常重要的机制,它允许我们在项目的配置阶段完成之后执行相应的操作,这样可以确保用户的自定义配置被完全考虑在内。当我们将自定义逻辑放在 <span>afterEvaluate</span> 中时,Gradle 会先完成对所有用户配置的解析和应用,包括那些在 <span>build.gradle</span> 或其他配置文件中显式指定的属性,然后再执行自定义的操作。

项目依赖项

在打包过程中,需要对不同 scope 的依赖进行处理,这涉及到 Gradle 的依赖管理。Gradle 中通常用两个 Classpath 来进行管理:

  • compileClasspath​:编译依赖项,此路径下的依赖主要用于项目编译阶段。例如,项目使用特定的数据库连接库进行数据访问层代码的编写,在编译时,需要将该数据库连接库的相关 jar 包包含在 compileClasspath 中,这样编译器才能识别并正确编译涉及数据库操作的代码。编译依赖项确保了代码在编译期间能够顺利通过语法检查和类型校验,为后续的运行奠定基础。
  • runtimeClasspath​:运行时依赖项,这些依赖是项目在实际运行过程中所必需的。以一个基于 Web 的应用为例,在运行时可能需要 Servlet 容器相关的依赖,这些依赖并不一定在编译阶段就绝对必要,但在应用启动和处理用户请求时是不可或缺的。运行时依赖项保证了项目在运行环境中能够正常执行各项功能。

在 Gradle 配置文件中通过 implementation、runtimeOnly 等声明的依赖项,最终会根据不同的阶段分类到上述的两个 classpath 中。例如,使用 implementation 'com.example:library:1.0.0' 声明的依赖,会在编译阶段添加到 compileClasspath,同时也会在运行时存在于 runtimeClasspath,因为 implementation 配置表示该依赖对于编译和运行都至关重要。而像 runtimeOnly 'com.example:runtime-only-library:1.0.0' 声明的依赖,则只会被添加到 runtimeClasspath,因为它仅在运行时才需要。

在 Gradle 中的 Action 中,通过获取 runtimeClasspath 配置,可以对运行时的依赖项进行分类、筛选、过滤等操作。例如,项目在运行时可能依赖多个日志库,但由于某些原因,需要对日志库进行优化,只保留特定的日志库进行打包。我们便可以在 SOFAArk 打包过程中,通过自定义配置 exclude 设置依赖项的标识​(groupId、artifactId 和 version)​,去除不需要的日志库依赖。

启动类和容器类

在 Ark 包的打包过程中,会对所有的依赖项进行分类,根据不同的类别,分为 Biz 包、Container 包,以及 Container 包的启动类相关的内容。用户在使用之前,如果没有指定相关包的配置项,会启用默认配置,从远程仓库或者本地仓库中获取到 sofa-ark-all 内容,并在配置阶段进行处理。此外,涉及到 Biz 包时,需要先将项目的所有 Biz 包打包出来后,再将这些 Biz 包写入到 Ark 包中。

想要实现上述的这些内容,并不需要自己去另外编写太多的代码,Gradle 提供了 Copy 和 CopySpec 两个工具。通过它们,我们可以极为方便地将依赖、配置项等各种内容输出到指定的目录。在使用这些工具时,我们只需要编写相应的过滤和操作规则,就能够精确地控制哪些内容需要被复制,哪些内容需要被排除,以及如何将它们按照我们期望的方式组织到目标目录中。

//定义目标目录为包的根目录
this.bootInfSpec = project.copySpec().into("");
bootInfSpec.into("", 定义过滤规则));
bootInfSpec.into("lib", 定义lib下面的过滤规则));

除了 Copy 和 CopySpec,Gradle 还提供了 CopyAction 对文件进行复制操作。CopyAction 的核心功能是将文件从一个位置复制到另一个位置,这是构建系统中常见的操作,尤其是在将资源、依赖项或生成的输出文件部署到相应的目录时。它不仅仅是简单的文件复制,还可以根据复制细节​(CopySpec​)来决定哪些文件需要复制,如何复制,以及复制时需要进行哪些处理。再最终将资源和内容写入到 jar 包时的操作,便可以集中到自定义的 CopyAction 中来实现。

插件调试

初步完成插件的编写工作后,想要在本地调试需要三步:

  • 发布到 Maven 仓库
  • 项目引入
  • 断点调试

本地发布需要在插件项目的 <span>build.gradle</span> 中设置如下:

plugins {
//    本地调试用,发布到maven
    id 'maven-publish'
}

另外还需要对 publish 进行配置,配置完成发布到本地仓库后,就可以在想要测试的 Gradle 项目中进行引入,这里一般要设置测试项目中的 <span>setting.gradle</span><span>build.gradle</span> 文件,指定插件仓库和版本。最后,通过打断点启动插件,就可以对插件进行调试。

项目未来

目前,Gradle 打包依然还有一些特性亟待解决和优化,包括即将支持的 declared 模式,优化 Ark 打包过程,抽离公用代码等内容。后续,我会进一步优化以上内容,使 Gradle 版本打包体验完成从可用到优雅的跃迁。

开源之夏个人随访

自我介绍

大家好,我是​魏照华​。第一次了解到开源活动,是看到身边同学参加谷歌开源之夏的经历,当时为我推开了通往新世界的大门。我在随后也参与了一些国内外的活动,在此过程中,逐渐感受到开源精神和开源项目对世界产生的深刻影响。

参与该项目的原因​

本次能参与 SOFAArk 打包插件项目,于我而言是份特别的缘分——三年前在社区发起的 SOFAArk 源码解析活动中,我注意到一个关于支持 Netty 插件的 issue,当时利用闲暇时间尝试提交了 PR,并幸运地被合并到主分支。未曾想两年后的今天,可以再次参与 SOFAArk 项目。

如何克服项目过程中的困难与挑战

就个人成长而言,我想分享以下两点:技术沟通的艺术与​时间管理的哲学​。

我本身并不擅长沟通,但是在项目实施中,我愈加体会到沟通是贯穿项目全周期的生命线。从前期与导师反复推敲项目目标、确定交付标准,到开发阶段针对方案的多轮技术探讨,直至后期维护方案的持续演变,每个环节都印证着一个事实——高质量的沟通本身就是技术实现的重要组成部分。这种认知让我开始有意识地培养自己的技术表达和沟通能力。

而在时间管理维度上,由于此次项目的实施阶段,我已经毕业参加工作,平衡全职工作与开源贡献的挑战远超预期。特别是程序开发的工作时间往往随着项目的进度“灵活安排”,面对职业任务与开源承诺的双重时间需求,我不得不直面资源分配的残酷现实:前期因在 Gradle 插件 API 上面花费了大量精力,恍然间发现时间竟已悄悄过半;中期在昼夜颠倒的编码调试中,又不得不妥协于某些有趣构想只能置于脑海。这种“时间赤字”的困境,最终转化为对敏捷规划和碎片时间利用上的重新审视和思考。

有哪些感想

站在这个节点回望,非常感谢这次社区给予的机会。我会重新出发,继续深耕开源这片土壤。​因为真正的开源精神,本就是场永不停歇的接力——我们既是前人智慧结晶的继承者,也是未来技术图景的脚手架搭建者​。

参考链接

[1]:https://www.sofastack.tech/projects/sofa-boot/sofa-ark-build-package-plugin/

相关文章
QGS
|
前端开发 easyexcel Java
手拉手EasyExcel实现web上传下载(全栈)
EasyExcel实现web上传下载
QGS
634 2
|
Unix Linux iOS开发
振南技术干货集:各大平台串口调试软件大赏(4)
振南技术干货集:各大平台串口调试软件大赏(4)
|
4月前
|
编解码 缓存 Java
Java 高效实现 WAV 音频拼接彻底摆脱 FFmpeg 的轻量本地方案
本文介绍一种纯Java实现的高效WAV音频拼接方案,无需依赖FFmpeg。通过解析WAV文件结构,利用内存映射与流式写入,实现零转码、低CPU占用的高性能拼接,适用于TTS、播客、嵌入式等场景,具备跨平台、易部署、高稳定性的优势。
Java 高效实现 WAV 音频拼接彻底摆脱 FFmpeg 的轻量本地方案
|
6月前
|
弹性计算 关系型数据库 数据安全/隐私保护
《突破Unity+阿里云联机瓶颈:多人游戏同步延迟与数据安全的双维度优化》
本文结合真实案例,拆解Unity与阿里云结合的多人联机游戏在“实时同步延迟”和“玩家数据安全”上的优化路径。针对同步延迟,通过“差异化增量同步”降低ECS带宽占用,结合GME时间同步与“预测回滚”减少判定偏差;数据安全方面,用SSL和GME端到端加密保障传输,以“加盐哈希+KMS加密”及RDS日志审计强化存储防护。还借阿里云弹性伸缩动态调度ECS资源,结合Unity分块加载与阿里云CDN优化资源加载。最终提升游戏流畅度与安全性,降低运营成本,为相关开发提供实践参考。
365 2
|
6月前
|
分布式计算 Java 关系型数据库
SpringBoot集成powerJob实战派
PowerJob 是全新一代分布式任务调度与计算框架,支持可视化管理、多种定时策略、丰富的执行模式(如单机、广播、Map/MapReduce),并提供工作流编排、在线日志、高可用及分布式计算能力,适用于定时任务、集群执行、延迟处理等场景。
1077 1
SpringBoot集成powerJob实战派
|
10月前
|
搜索推荐 Java 定位技术
Java实现利用GeoLite2-City.mmdb根据IP定位城市的方法
在城市,国家,地区等地理位置数据获取之后,你可以依指定的业务需求,来进行进一步的数据处理。例如,你可以设计一个应用,根据用户的 IP 地址来个性化地展示内容,或者用于分析网络请求的来源等。
1830 20
|
SQL 资源调度 Oracle
实时计算 Flink版产品使用合集之是否支持通过 TRUNCATE TABLE 语句来截断(truncate)表
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
存储 Java 数据库连接
mybatis精讲(三)--标签及TypeHandler使用
mybatis精讲(三)--标签及TypeHandler使用
|
弹性计算 Kubernetes 网络协议
阿里云弹性网络接口技术的容器网络基础教程
阿里云弹性网络接口技术的容器网络基础教程
阿里云弹性网络接口技术的容器网络基础教程
|
Android开发 计算机视觉 C++
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
音视频编程对许多程序员来说是一片充满挑战的领域,但借助如OpenCV、LearnOpenGL、FFmpeg、OBS Studio及VLC media player等强大的开源工具,可以降低入门门槛。这些框架不仅覆盖了计算机视觉、图形渲染,还包括多媒体处理与直播技术,通过多种编程语言如Python、C++的应用,使得音视频开发更为便捷。例如,OpenCV支持跨平台的视觉应用开发,FFmpeg则擅长多媒体文件的处理与转换,而VLC media player则是验证音视频文件质量的有效工具。
666 0
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架

热门文章

最新文章