高效使用Java构建工具|Maven篇|云效工程师指北

简介:高效使用Java构建工具|Maven篇。众所周知,当前最主流的Java构建工具为Maven/Gradle/Bazel,针对每一个工具,我将分别从日常工作中常见的场景问题切入,例如依赖管理、构建加速、灵活开发、高效迁移等,针对性地介绍如何高效灵活地用好这3个工具。

大家好,我是胡晓宇,目前在云效主要负责Flow流水线编排、任务调度与执行引擎相关的工作。

作为一个有多年Java开发测试工具链开发经验的CRUD专家,使用过所有主流的Java构建工具,对于如何高效使用Java构建工具沉淀了一套方法。众所周知,当前最主流的Java构建工具为Maven/Gradle/Bazel,针对每一个工具,我将分别从日常工作中常见的场景问题切入,例如依赖管理、构建加速、灵活开发、高效迁移等,针对性地介绍如何高效灵活地用好这3个工具。

Java构建工具的前世今生

在上古时代,Java的构建都在使用make,编写makefile来进行Java构建有非常多别扭与不便的地方。

紧接着Apache Ant诞生了,Ant可以灵活的定义清理编译测试打包等过程,但是由于没有依赖管理的功能,以及需要编写复杂的xml,还是存在着诸多的不便。

随后Apache Maven诞生了,Maven是一个依赖项管理和构建自动化工具,遵循着约定大于配置的规则。虽然也需要编写xml,但是对于复杂工程更加容易管理,有着标准化的工程结构,清晰的依赖管理。此外,由于Maven本质上是一个插件执行框架,也提供了一定的开放性的能力,我们可以通过Maven的插件开发,为构建构成创造一定的灵活性。

但是由于采用约定大于配置的方式,丧失了一定的灵活性,同时由于采用xml管理构建过程与依赖,随着工程的膨胀,配置管理还是会带来不小的复杂度,在这个背景下,集合了Ant与Maven各自优势的Gradle诞生了。

Gradle也是一个集合了依赖管理与构建自动化的工具。首要的他不再使用XML而是基于Groovy的DSL来描述任务串联起整个构建过程,同时也支持插件提供类似于Maven基于约定的构建。除了在构建依赖管理上的诸多优势之外,Gradle在构建速度上也更具优势,提供了强大的缓存与增量构建的能力。

除了以上Java构建工具之外,Google在2015年开源了一款强大,但上手难度较大的分布式构建工具Bazel,具有多语言、跨平台、可靠增量构建的特点,在构建上可以成倍提高构建速度,因为它只重新编译需要重新编译的文件。Bazel也提供了分布式远程构建和远程构建缓存两种方式来帮助提升构建速度。

目前业内使用Ant的人已经比较少,主要都在用Maven、Gradle和Bazel,如何真正基于这三款工具的特点发挥出他们最大的效用,是这个系列文章要帮大家解决的问题。先从Maven说起。

优雅高效地用好Maven

当我们正在维护一个Maven工程时,关注以下三个问题,可以帮助我们更好的使用Maven。

● 如何优雅的管理依赖
● 如何加速我们的构建测试过程
● 如何扩展我们自己的插件

优雅的依赖管理

在依赖管理中,有以下几个实践原则,可以帮助我们优雅高效的实现不同场景下的依赖管理。

● 在父模块中使用dependencyManagement,配置依赖
● 在子模块中使用dependencies,使用依赖
● 使用profiles,进行多环境管理

以我在日常开发中维护的一个标准的spring-boot多模块Maven工程为例。

工程内各个module之间的依赖关系如下,通常这也是标准的 spring-boot restful api多模块工程的结构。

便捷的依赖升级

通常我们在依赖升级的时候会遇到以下问题:

● 多个依赖关联升级
● 多个模块需要一起升级

在父模块的pom.xml中,我们配置了基础的spring-boot依赖,也配置了日志输出需要的logback依赖,可以看出,我们遵循了以下的原则:

(1)在所有子模块的父模块中的pom中配置dependencyManagement,统一管理依赖版本。在子模块中直接配置依赖,不用再纠缠于具体的版本,避免潜在的依赖版本冲突。
(2)把groupId相同的依赖,配置在一起,比如groupId为org.springframework.boot,我们配置在了一起。
(3)把groupId相同,但是需要一组依赖共同提供功能的artifactId,配置在一起,同时将版本号抽取成变量,便于后续一组功能共同的版本升级。比如spring-boot依赖的版本抽取成了spring-boot.version。

在子模块build-engine-api的pom.xml中,由于在父pom中配置了 dependencyManagement中依赖的spring-boot相关依赖的版本,因此在子模块的pom中,只需要在dependencies中直接声明依赖,确保了依赖版本的一致性。

合理的依赖范围

Maven依赖有依赖范围(scope)的定义,compile/provieded/runtime/test/system/import,原则上,只按照实际情况配置依赖的范围,在必要的阶段,只引入必要的依赖。

90%的Java程序员应该都使用过org.projectlombok:lombok来简化我们的代码,其原理就是在编译过程中将注解转化为Java实现。因此该依赖的scope为provided,也就是编译时需要,但在构建出最终产物时又需要被排除。

当你的代码需要使用jdbc连接一个mysql数据库,通常我们会希望针对标准 JDBC 抽象进行编码,而不是直接错误的使用 MySQL driver实现。这个时候依赖的scope就需要设置为runtime。这意味着我们在编译时无法使用该依赖,该依赖会被包含在最终的产物中,在程序最终执行时可以在classpath下找到它。

在子模块dao中,我们有对sql进行测试的场景,需要引入内存数据库h2。

因此,我们将h2的scope设置为test,这样我们在测试编译和执行时可以使用,同时避免其出现在最终的产物中。

更多关于scope的使用,可以参考官方帮助文档。

多环境支持

举个简单的例子,当我们的服务在公有云部署时,我们使用了一个云上版本为8.0的MySQL,而当我们要进行专有云部署时,用户提供一个自运维的版本为5.7的MySQL。因此,我们在不同的环境中使用不同的 mysql:mysql-connector-java 版本。

类似的,在项目实际的开发过程中,我们经常会面临同一套代码。在多套环境中部署,存在部分依赖不一致的情况。

关于profiles的更多用法,可以参考官方帮助文档

依赖纠错

如果你已经在父pom中使用dependencyManagement来锁定依赖版本,大概率的,你几乎很少会碰到依赖冲突的情况。

但是当你还是意外的看到了NoSuchMethodError,ClassNotFoundException 这两个异常的时候,有以下两个方法可以快速的帮你纠错。

(1)通过依赖分析找到冲突的依赖

(2)通过添加stdout代码找到冲突的类实际是从哪个依赖中查找的

通过具体的路径中对应的版本信息,找到对应的版本并校正。

当然这个方法也可以纠出一些依赖被错误的加载到classpath下,非工程本身依赖配置引起的冲突。

测试构建过程加速

作为一个开发者,总会希望我们的工程无论在什么情况下,执行的又快又稳,那么在Maven的使用过程中,需要遵循以下原则。

● 尽可能复用缓存
● 尽可能的并行构建或测试

依赖下载加速

通常情况下,根据Maven配置文件 ${user.home}/.m2/settings.xml 中的配置,默认情况下是缓存在${user.home}/.m2/repository/。

通常在构建过程中,依赖的下载往往会成为比较耗时的部分,但是通过一些简单的设置,我们可以有效的减少依赖的下载与更新。

● 优化updatePolicy设置
updatePolicy指定了尝试更新的频率。Maven 会将本地 POM 的时间戳(存储在存储库的 maven-metadata 文件中)与远程进行比较。选项包括:always(总是)、daily(每天,默认值)、interval:X(其中 X 是以分钟为单位的整数)、never(从不)。

● 使用离线构建
除此之外,如果构建环境已经存在缓存,可以使用Maven的offline模式进行构建,避免依赖或插件的下载更新。

直观的,日志中将不会出现类似如下Downloading相关的信息。

构建过程加速

在默认情况下,Maven构建的过程并不会充分的使用你的硬件的全部能力,他会顺序的构建你的maven工程的每一个模块。这个时候,如果可以使用并行构建,那么将有机会提升构建速度。

以上是并行构建的两个命令,可以根据实际的cpu情况来选择对应的命令。但是如果你发现构建时间并没有得到减少,那么你的maven模块间可能存在类似的依赖,模块之间只是一个简单的传递。

那么并行构建对你来说并不适用,如果你的模块间依赖关系存在并行的可能,那么使用上述命令进行构建,才能使并行构建发挥效果。

测试过程加速

当我们尝试加速maven工程测试用例的部分,那么就不得不提到一个插件,maven-surefire-plugin。

当你在执行mvn test的时候,默认情况下就是surefire插件在工作。如果我们想在测试中使用并行的能力,可以作如下配置。

但是需要注意不恰当的使用并行能力进行测试,反而可能带来副作用。比如当parallel配置为methods,但是由于某些原因测试用例的执行之间存在顺序要求,反而会出现因为用例方法并行执行,导致用例失败,因此也倒逼我们,如果想获得更快的测试速度,case的编写也需要独立且高效。

更多关于surefire插件的使用,可以参考这篇文档。

Maven插件开发

maven本质上是一个插件执行框架,所有的执行过程,都是由一个一个插件独立完成的。关于maven的核心插件可以参考这篇文档。

maven默认为我们提供的这些插件比如maven-install-plugin/mvn-surefire-plugin/mvn-deploy-plugin外,还有一些三方提供的插件,单测覆盖率插件mvn-jacoco-plugin,生成api文档的swagger-maven-plugin等等。

在日常工作的过程中,我碰到了这样一个问题:有个存在明显问题的sql被发布到了预发布环境,同时由于预发与生产使用的是同一个db实例,由于sql的性能问题,影响了线上。

除了通过必要的code review准入,来避免类似的问题,更简单的,我们可以自己动手实现一个代码中sql扫描的插件,让代码在CI时直接失败掉,自动化的避免此类问题的发生。于是我们开发了一个maven插件,使用方法和效果如下:

在工程中引入我们开发并部署好的插件com.aliyun.yunxiao:mybatis-sql-scan。

执行以下命令,或其他包含validate阶段执行的命令。

我们将会在日志中看到如下插件执行的信息

在扫描出缺陷时,build失败,并会在日志中出现对应的信息:

在GlobalLockMapper.java这个文件中,我们有一条全表扫描的sql语句可能存在风险,

同时build失败。

接下来我会从如何开发这个异常sql扫描的maven插件入手,帮助大家了解插件开发的过程。

1、创建工程

生成的sample工程如下,

其中MyMojo.java定义了插件的入口实现,

此外在根pom.xml中可以看到,

● packaging为“maven-plugin”。
● 依赖配置中,依赖了一些插件开发的基础二方库。
● 插件节点下,依赖了maven-plugin-plugin协助我们完成插件的构建。

2、Mojo实现

在开始实现我们的Mojo之前,我们需要做如下分析:

● 插件在maven的哪个生命周期执行
● 插件在执行时需要哪些入口参数
● 插件执行完成后怎么退出

由于我们要实现的插件是要做mybatis annotation扫描比如 @Update/@Select,判断是否有异常的sql,比如是否存在全表扫描的sql,是否存在全表更新的sql等,对于此种场景下,

● 由于需要扫描特定的源码,需要知道工程源码的所在目录,以及扫描哪些文件
● 插件扫描出异常时,只要报错即可,不用产出任何报告
● 希望在后续执行mvn validate时触发扫描

那么预期中的插件是这样的,

那么,

● @Mojo(name = "check") 定义了goal
● @Parameter
○ @Parameter(defaultValue = "${project}", readonly = true) 参数绑定了工程的根目录 ,project.getCompileSourceRoots()便可以获取到源代码的根路径
○ 我们定义了mapperFiles,用来负责扫描哪些文件的通配,excludeFiles用来负责排除哪些文件
● execute()
○ 有了以上的基础,在execute方法中我们便可以实现对应的逻辑,当扫描结出异常的sql时,抛出MojoFailureException异常,插件便会失败终止。

以上,我们便完成了一个插件的基本能力的开发。

3、插件的打包与上传

插件开发完成后,我们可以通过配置distributionManagement,然后执行mvn deploy,完成插件的构建与发布。

希望通过我的介绍,能够帮助大家更好的使用maven,下一篇我们讲Gradle,欢迎持续关注我们。

原文链接

本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/511111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

布局云与边缘之后,Akamai 为何加码安全领域

作者 | 宋慧 出品 | CSDN 云计算 随着云的深入和普及,云上的安全也变得愈加重要。CSDN 系列技术直播栏目《大咖来了》就曾重点讨论 云上安全的攻防之道 ,以及云原生的安全发展。 最近,发明 CDN 技术的资深技术厂商 Akamai,继增强…

Dubbo-go 服务代理模型

简介:HSF 是阿里集团 RPC/服务治理 领域的标杆,Go 语言又因为其高并发,云原生的特性,拥有广阔的发展前景和实践场景,服务代理模型只是一种落地场景,除此之外,还有更多的应用场景值得我们在研发的…

探索AI视觉技术新应用,夸克扫描王首推“离线模式”端侧AI算法提升隐私安全

手机扫描正在超越传统扫描仪,给大学生和职场人带来更高效、更便捷的信息服务体验。 在基于手机相机功能的搜索行为中,大学生的学习场景占比超过一半。 手机扫描的“离线模式”,让夸克成为第一个将扫描AI算法上端的App。 各大高校开学在即&…

作业帮云原生降本增效实践之路

简介:目前,作业帮已经和阿里云有一个关于 AEP 的 tair 方案的结合,在新的一年希望我们有更大规模的落地。文章里讲得比较多的是关于降本做的一些技术改进,其实在降本增效这里面还有很大一块工作量是运营,成本运营我们也…

基于 Serverless 打造如 Windows 体验的个人专属家庭网盘

简介:虽然现在市面上有些网盘产品, 如果免费试用,或多或少都存在一些问题, 可以参考文章《2020 国内还能用的网盘推荐》。本文旨在使用较低成本打造一个 “个人专享的、无任何限速的、如 Windows 体验的私有云盘”。 作者 | 西流…

Apsara Stack 技术百科 | 数字化业务系统安全工程

简介:数字化平台已经与我们生活紧密结合,其用户规模庞大,一旦系统出现故障,势必会造成一定生活的不便。比如疫情时代,健康码已经成为人们出门必备的条件,一旦提供健康码服务平台出现故障,出行将…

支撑百万级传感器的延时队列

文/升哲科技 刘鹏 摘要:本文主要描述升哲科技在打造物联智慧城市平台过程中关于如何实现延时队列服务的技术选型经验、延时队列服务的架构设计以及延时队列的底层细节实现原理。 背景 升哲科技是一家物联网与人工智能领域的国家高新技术企业、独角兽企业。 要打…

深度解析|基于 eBPF 的 Kubernetes 一站式可观测性系统

简介:阿里云 Kubernetes 可观测性是一套针对 Kubernetes 集群开发的一站式可观测性产品。基于 Kubernetes 集群下的指标、应用链路、日志和事件,阿里云 Kubernetes 可观测性旨在为 IT 开发运维人员提供整体的可观测性方案。 作者:李煌东、炎…

系列解读SMC-R:透明无感提升云上 TCP 应用网络性能(一)| 龙蜥技术

简介:已有的应用若想使用RDMA技术改造成本高,那么有没有一种技术是不做任何改造就可以享受RDMA带来的性能优势? 文/龙蜥社区高性能网络SIG 引言 Shared Memory Communication over RDMA (SMC-R) 是一种基于 RDMA 技术、兼容 socket 接口的内…

技术引领未来, IDC TechScape中国数据安全发展路线图首发

2022年8月26日,IDC 2022 CSO全球网络安全峰会(中国站)在上海隆重开幕,会上首次发布《IDC TechScape:中国数据安全发展路线图,2022》。报告认为,帮助用户构建全方位数据安全治理体系将成为大趋势…

DataV 3D 平面地图 2.0 焕新上线

简介:DataV3月,3D平面地图2.0现已上线~ 3D 平面地图 2.0 现已上线~ 让我们来看看更新了哪些功能吧! 01 交互升级,省市区自由下钻 自带行政区域数据,无需配置: 甚至,可以通过「蓝图编辑器」实…

PolarDB-X 发布 2.1.0 版本,Paxos 开源

简介:2022年4月1号,PolarDB-X 正式开源X-Paxos,基于原生MySQL存储节点,提供Paxos三副本共识协议,可以做到金融级数据库的高可用和容灾能力,做到RPO0的生产级别可用性,可以满足同城三机房、两地三…

828成首个B2B企业节,华为联合3万生态伙伴助力中小企业数字化转型

中小企业既是市场的主体,也是保就业的主力军。截至2021年末,中小企业在全国企业中数量占比已超过99%,并贡献了80%的就业机会。 为助力中小企业创新发展,8月28日,华为联合3万家生态伙伴,共同发起了全国首个…

阿里云贾扬清:数据湖正成为企业数据应用创新标配

简介:全球数据湖峰会开幕 数字经济蓬勃发展的今天,越来越多的用户已经从“上好云”,走到了“用好云”的这个阶段。如果说在“上好云这个阶段,大多数用户关心的是如何在成本上获得更好的回报。那么在上好云这个阶段,更…

强强联手,NVIDIA 与 Ampere Computing 重磅推出云原生服务器平台

随着 5G、元宇宙的兴起,云游戏再一次迎来爆发。据 IDC 与中国信息通信研究院联合发布的《全球云游戏产业深度观察及趋势研判(2022年)》显示,2021年,中国地区云游戏市场收入已达 40.6 亿元,同比增长 93.3%。…

有了这款工具,定位线上问题事半功倍|云效工程师指北

简介:有了这款工具,定位线上问题事半功倍,程序员在日常工作中经常会遇到一些线上问题需要排查,本文的主人公程序员小张也不例外。但排查的过程却时常令他困扰不已。让我们一起看看他遇到了哪些问题,又是怎么解决的。 …

云原生时代如何用 Prometheus 实现性能压测可观测-Metrics 篇

简介:可观测性包括 Metrics、Traces、Logs3 个维度。可观测能力帮助我们在复杂的分布式系统中快速排查、定位问题,是分布式系统中必不可少的运维工具。 作者:拂衣 什么是性能压测可观测 可观测性包括 Metrics、Traces、Logs3 个维度。可观测…

基于 KubeVela 的机器学习实践

简介:本文主要介绍如何使用 KubeVela 的 AI 插件,来帮助工程师更便捷地完成模型训练及模型服务。 作者:KubeVela 社区 在机器学习浪潮迸发的当下,AI 工程师除了需要训练、调试自己的模型之外,还需要将模型进行部署上…

Gartner发布2022年云平台服务技术成熟度曲线,iPaaS、低代码将达到成熟期

Gartner 2022年云平台服务技术成熟度曲线显示,集成平台即服务(iPaaS)和低代码应用平台(LCAP)技术将在不到两年的时间内达到生产成熟期(Plateau of Productivity)。 编辑 | 宋慧 供稿 | Gartner…

贼喊捉贼?“盗版”软件开发者向 GitHub 投诉被侵权

整理 | 于轩 出品 | CSDN(ID:CSDNnews)拥有超过2亿个代码存储库,由8000多万用户共享,GitHub已然成为世界上最大和最先进的开发平台。 与其他托管用户生成内容的平台一样,这个庞大的代码库经常会接到版权…