Java 9 模块化特性学习:一个使用Gradle构建模块化项目的实践指南

Java 9 模块化特性学习:一个Gradle模块化项目实践

前言

不知怎么的,现今的程序员往往被当成加班工种的典范,而我随着工龄的不断增加,作为码农的我码带码的时间却可以做到越来越少?(狗头)
时间的节省一部分归功于之前写过的代码,后续就可以拿来参考复用;一部分归功于现今的开源技术,有很多优秀的开源API可以直接依赖,拿来即用;一部分归功于不断提高的写总结和写文档的能力,编程思路梳理清楚了,自然而然的写代码埋坑和不断填坑的时间就会减少;还有一部分归功于现今的AI技术,比如GitHub Copilot 和当下比较火的 chatGPT,目前 GitHub Copilot 可以帮助我减少写那些逻辑简单的重复代码的时间 ;chatGPT 则被我用做私人资料查询库,有什么知识点需要,都可以先用chatGPT查一下,然后它会给我提供比较满意的答案。比起使用百度,google 在众多文章中淘金,chatGPT 提供的答案往往可以做到一针见血,是相当不错的工作伴侣。
而节省码带码时间最重要的一点,就是作为一个程序员一定要去写更优秀的代码。一个可拓展的,复用性高的,可维护性好的优秀代码,可以节省出程序员百分之五十的做重复需求的时间。而如果将这些时间再用于code review ,去提高自己的代码质量,并同时提高自己的编程水平和编程思路,那么做无聊纯粹码代码工作的时间就会越来越少,而用于探索新知识,新技术的时间就会增多,搞编程的乐趣慢慢涌现出来,突然想起快乐星球头上一根天线的天线宝宝。。。嘿嘿,头像就是它了。
前言写了这么多却没有进入正题,是我觉得作为一个打工人,思考清楚自己每天都在做什么是至关重要的。作为程序员我们每天是在不断埋坑,填坑的车轱辘里面打转?还是每天在为自己后续的编程路上添砖加瓦?思考过后,希望大家一起共勉。

项目简介

本次要介绍的项目,是最近我做Code Review 的一个小项目getPush。这个项目一开始是我在2022年2月写的,主要做文件获取,文件解析,文件生成,文件发送这四件事情。项目上线后,多个城市部署使用,基本没有什么运维问题,我觉得算我比较满意的作品。最近一个需求中又正好需要用到这个程序,我便借这个机会再给这个项目优化一下。
而这次优化,改动比较大,我便直接新建了一个项目,之前使用的maven 构建,这次替换成了Gradle 构建,并使用了Java 17 以及Java 9 特性中的模块化技术去搭建这个项目。本次Code Review 的目的有以下几点:

  • 实现业务代码,技术代码的完全分离,为软件开源做准备
  • 使用Module 技术去掉代码中的无效依赖,减少代码包字节大小,为后续将项目作为热插拔插件使用做准备
  • 代码结构调整,减少代码重复率;SonarLint 代码检查,减少程序中问题代码
  • 文档完善,编写更加利于用户使用的规范文档
  • 前端优化,准备使用React 编写前端,并增加页面交互更利于用户自己配置和使用这个项目

本次项目分享的重点不在于项目,而是这个项目是如何使用 gradle 和模块化的,所以这次分享中不含有项目的概要设计,详细设计和操作文档。

项目结构简介

getPush项目结构简介
项目主要分为五个module

  1. common-data 数据仓储

  2. common-template 项目核心module,因为对于文件获取,文件解析,文件生成,文件发送这四个功能,我使用了模板设计模式,所以起名叫template

  3. common-util 项目工具包

  4. web 前后端交互接口的后端部分

  5. biz 具体业务封装,里面会再根据不同的业务需求封装不同的module子项目

    如果项目实现开源的话,用户需要自己去实现 biz module,去完成指定业务需求;对于文件获取,文件发送,只需在前端添加配置即可实现;对于文件解析,可以使用common-util 提供的Bean反射方法,只需编写接收数据的Bean 对象即可实现文件解析。而文件生成则需要用户自己继承template的生成接口,然后编写文件生成的业务逻辑。getpush程序提供了完善的日志,去记录每条任务处理结果,同时getpush也提供了手动处理页面和批次处理文件的方法。

项目设计简介

在这里插入图片描述

gradle配置简介

get-push总项目的 build.gradle 配置

plugins {id 'java'id 'io.spring.dependency-management' version '1.1.0'id 'org.javamodularity.moduleplugin' version '1.8.1-SNAPSHOT' apply false
}plugins {id 'java'id 'io.spring.dependency-management' version '1.1.0'id 'org.javamodularity.moduleplugin' version '1.8.1-SNAPSHOT' apply false
}group = 'com.rtzn'
version = '1.0.0'
sourceCompatibility = '17'subprojects {group = 'com.rtzn'version = '1.0.0'sourceCompatibility = '17'apply plugin: "org.javamodularity.moduleplugin"apply plugin: 'io.spring.dependency-management'java {modularity.inferModulePath = true}repositories {mavenLocal()maven { name "Alibaba"; url "https://maven.aliyun.com/repository/public"}maven { name "Alibaba-gradle-plugin"; url "https://maven.aliyun.com/repository/gradle-plugin/" }mavenCentral()}buildscript {repositories {mavenLocal()maven { name "Alibaba"; url 'https://maven.aliyun.com/repository/public' }}}test {useJUnitPlatform()testLogging {events 'PASSED', 'FAILED', 'SKIPPED'}}dependencies {compileOnly 'org.projectlombok:lombok:1.18.22'annotationProcessor 'org.projectlombok:lombok:1.18.22'implementation 'cn.hutool:hutool-all:5.8.11'implementation 'org.slf4j:slf4j-api:1.7.32'implementation 'ch.qos.logback:logback-classic:1.2.9'testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'testImplementation 'org.junit.jupiter:junit-jupiter-params:5.3.1'testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'}
}
  1. plugins
  • java 插件:为Java项目提供了一些标准的任务和配置,例如编译Java代码、运行单元测试、打包Java类库等等。此外,Java插件还定义了一些约定,例如默认的源代码和资源目录结构,以及编译输出的默认位置。
  • dependency-management 插件:它的作用是简化构建过程中对第三方依赖的管理。
  • org.javamodularity.moduleplugin: 使用这个插件,可以通过在Gradle构建脚本中定义模块、声明模块之间的依赖关系、导出模块的API等,来轻松创建和管理Java 9及更高版本中的模块化应用程序
  1. subprojects :定义了所有子项目的公共配置内容
  • group 组,version 版本,sourceCompatibility jdk版本
  • apply plugin:定义子模块的公共插件
  • modularity.inferModulePath=true:Java运行时环境将自动推断模块路径,它会根据应用程序中的类路径和模块路径的默认规则,计算出模块路径中应该包含哪些模块。
  • repositories:仓储库,仓储库会按顺序加载,首先加载mavenLocal() 本地maven 库,然后本地库取不到依赖的再去加载 maven { name “Alibaba”; url “https://maven.aliyun.com/repository/public”} 阿里Maven镜像地址;
    maven { name “Alibaba-gradle-plugin”; url “https://maven.aliyun.com/repository/gradle-plugin/” } 阿里Gradle插件镜像地址;最后再去查 mavenCentral() maven 中央仓库。
  • buildscript 声明构建时先从本地库下载依赖,然后再从阿里Maven镜像地址下载依赖。
  • test:指定测试任务的行为和配置
    • useJUnitPlatform():指定使用JUnit 5平台来运行测试
    • testLogging:指定测试日志记录的级别和输出。在这个例子中,只输出测试结果为“PASSED”、“FAILED”或“SKIPPED”的测试日志记录。
  • dependencies 定义子项目的公共依赖

get-push总项目的 settings.gradle 配置

rootProject.name = 'getPush-new'
include('common-data', 'common-util', 'common-template','web','biz')
include('biz:bizsubproject')
  • rootProject.name:本项目名称
  • include(‘common-data’, ‘common-util’, ‘common-template’,‘web’,‘biz’):定义包含的子项目
  • include(‘biz:bizsubproject’) :定义子项目中包含的子项目

get-push子项目common-template的 build.gradle 配置

plugins {id 'java-library'
}
dependencies {implementation project(path: ':common-util')implementation project(path: ':common-data')implementation 'com.alipay.sdk:alipay-sdk-java:3.0.52.ALL'implementation 'org.apache.httpcomponents:httpclient:4.5.14'implementation('org.springframework:spring-context:6.0.6') {exclude group: 'org.springframework', module: 'spring-jcl'}implementation('org.springframework:spring-jdbc:6.0.6') {exclude group: 'org.springframework', module: 'spring-jcl'}implementation 'com.baomidou:mybatis-plus-core:3.5.3.1'implementation 'com.baomidou:mybatis-plus-extension:3.5.3.1'implementation 'com.jcraft:jsch:0.1.55'
}
  • plugins:java-library:当应用java-library插件时,Gradle将默认按照Java库的约定进行配置和构建
  • implementation project(path: ‘:common-util’): 依赖引用另一个子项目 common-util
  • implementation(‘org.springframework:spring-jdbc:6.0.6’) {exclude group: ‘org.springframework’, module: ‘spring-jcl’}:引用 spring-jdbc 6.0.6,但不引用其 spring-jcl 依赖。spring-jcl依赖用于实现Spring框架中的日志抽象层,而我程序的日志使用了logback依赖;在模块化项目中这两个依赖不能同时引用。

get-push子项目common-template的 settings.gradle 配置

rootProject.name = 'common-template'

模块化的必要java类 module-info

common-template 的 module-info 示例

module common.template.main {// 依赖的 二方库requires common.util.main;requires common.data.main;// 依赖的 三方库requires spring.context;requires hutool.all;requires alipay.sdk.java;requires org.apache.httpcomponents.httpclient;requires org.apache.httpcomponents.httpcore;requires spring.jdbc;requires com.baomidou.mybatis.plus.core;requires com.baomidou.mybatis.plus.extension;requires jsch;// 提供反射类opens com.rtzn.commontemplate.config;opens com.rtzn.commontemplate.pojo.vo;// 提供接口provides com.rtzn.commontemplate.service.connect.ConnectServicewith com.rtzn.commontemplate.service.connect.ConnectByFTPServiceImpl, com.rtzn.commontemplate.service.connect.ConnectByHTTPServiceImpl,com.rtzn.commontemplate.service.connect.ConnectBySFTPServiceImpl, com.rtzn.commontemplate.service.connect.AlipayConnectImpl;provides com.rtzn.commontemplate.service.generate.GenerateFileServicewith com.rtzn.commontemplate.service.generate.GenerateFileServiceImpl;provides com.rtzn.commontemplate.service.handle.HandleFileServicewith com.rtzn.commontemplate.service.handle.HandleFileServiceImpl;exports com.rtzn.commontemplate.service.template;exports com.rtzn.commontemplate.config;exports com.rtzn.commontemplate.pojo.vo;exports com.rtzn.commontemplate.service.generate;exports com.rtzn.commontemplate.service.handle;}

module-info 基本语法

  • module:定义一个Java模块
  • requires: 声明当前模块所依赖的其他模块
  • exports:指定当前模块中哪些可以被其他模块访问
  • opens:指定当前模块中哪些包可以被其他模块反射访问
  • uses:声明当前模块使用的服务接口
  • provides: 声明当前模块提供的服务实现类
  • with:与provides 一起使用,指定服务实现类的实现方式

FAQ

不同子模块的 service ,mapper 如何实例化为 spring 容器中的bean对象,从而实现跨模块服务调用

通常,我们使用@ComponentScan注解来配置Spring应用程序的组件扫描路径;使用@MapperScan注解来配置MyBatis应用程序的Mapper接口扫描路径。
示例:

package com.rtzn.web;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;@SpringBootApplication
@ComponentScan(basePackages = {"com.rtzn.web.*", "com.rtzn.data.service", "com.rtzn.commontemplate.service","com.rtzn.demo.service"})
@MapperScan(basePackages = {"com.rtzn.data.mapper", "com.rtzn.demo.mapper"})
public class WebApplication {public static void main(String[] args) {SpringApplication.run(WebApplication.class, args);}
}

mabatis-plus 的 mapper.xml 路径多模块配置

mybatis-plus:# Mapper.xml 文件位置 Maven 多模块项目的扫描路径需以 classpath*: 开头mapperLocations: classpath*:/mapperxml/*.xml

问题

  1. 目前Gradle plugin中没有找到一款像 mavenHelper的插件来更方便的进行 gradle 的依赖管理,有什么关于gradle 进行依赖管理的推荐吗?
  2. 再进行 java application 模块化的过程中,遇到了很多项目模块化后无法访问API依赖的难题 。比如
    because module common.data.main does not read unnamed module @0x301ec38b
    需要在build.gradle 中加入
run {jvmArgs = ['--illegal-access=permit', '--add-opens', 'com.rtzn.web.WebApplication=ALL-UNNAMED']
}

module java.base does not "opens java.lang" to module spring.core
需要在启动java 命令时加入 --add-opens java.base/java.lang=spring.core
我想找到一个完善的 gradle 模块化项目已供我参考,来进行后续项目的优化和提高,有什么好的项目推荐吗?

学习链接

gradle 学习

  • gradle 官网文档:https://docs.gradle.org/current/userguide/userguide.html
    模块化学习
  • oracle 官网文档:https://docs.oracle.com/javase/9/docs/api/java/lang/module/package-summary.html

总结

时光荏苒,小编写完这篇文章已经过了3个小时,时光回溯,小编重构这个项目可是花了整整一周时间,期间还不忘利用业余时间,王者上了巅峰1900百分。而阅读文章的你可能仅仅两三分钟就看完了一篇文章,阅读文章是咱们技术学习的一个方式,但我认为不是最好的方式。
在我看来,学习一门技术最好的方式就是先详细阅读它的官网文档,而阅读官网文档最好的方式就是不用翻译软件,而直接原文去阅读这个官网正品文档。所以,各位有缘再见,小编要去学英语了。good bye!see you nala。

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

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

相关文章

Generative AI 新世界:大型语言模型(LLMs)概述

在上一篇《Generative AI 新世界:文本生成领域论文解读》中,我带领大家一起梳理了文本生成领域(Text Generation)的主要几篇论文:InstructGPT,RLHF,PPO,GPT-3,以及 GPT-4…

大语言模型经典论文一次读到爽!

知乎:Ostrich 职位:阿里巴巴 算法工程师 原文:https://zhuanlan.zhihu.com/p/620360553 要说2023刷屏最多的词条,ChatGPT可以说是无出其右。到最近的GPT-4,技术的革新俨然已呈现破圈之势,从学术圈到工业界再…

关于两个STM32F103系列单片机的蓝牙通信

毕设做的是掌控小车,因此采用蓝牙通信作为小车和手部通信,前段时间做出实物,对其遇到的问题以及解决的方法做一些总结。一个主控芯片采用STM32F103ZET6,另一个主控芯片采用STM32F103C8T6,原因是本来准备了两个主控C8T6…

GraphPad绘图软件:汇集生物统计、化学统计、以及科技绘图于一身

分享一款实用的绘图软件,GraphPad Prism。汇集生物统计、化学统计、以及科技绘图于一身,有超过110个国家的超过20万名科学家用这个软件来分析、绘制和展示他们的科学数据。 不需要学习复杂的编程,无需代码,用起来像EXCEL一样点点点…

认真分享几个「副业赚钱」的靠谱思路!

已剪辑自: https://mp.weixin.qq.com/s?__bizMzUxODM4MDk2NA&mid2247486581&idx1&sn1a27953f0956836693434f9aaf96829f&chksmf98880beceff09a83a915d231b5888287142227fda6671d53dac7d03e2c13806abe82994a3b6&scene21#wechat_redirect 你好,我…

如何在家里赚钱,分享六个适合普通人长期可做的副业

​当今社会,压力越来越大,工作、家庭、生活等等,方方面面都需要钱,仅靠一份工作赚钱,已经很难满足我们的需求。所以越来越多的人尝试做副业,通过副业增加收入,让生活过得更幸福。常见的副业都是…

ChatGPT对软件开发生命周期有哪些冲击?

1、对需求开发的冲击 ChatGPT对需求开发的冲击,主要体现在:可以帮助更准确地理解和记录需求,协助起草和完善用户故事或用例。 ChatGPT对软件开发生命周期有哪些冲击? ​ 2、对设计的冲击 ChatGPT对设计的冲击,主…

元宇宙场景技术实践|实现“虚拟人”自由

虚拟形象是虚拟世界的核心资产,也是打造元宇宙社交的数字名片,从虚拟形象为切入点,ZEGO Avatar 基于强大的 AI 算法能力,可以为企业提供多元化风格虚拟形象制作及智能互动服务,助力企业打造虚拟形象数字资产&#xff0…

元宇宙大潮来袭?业内首个虚拟形象实时互动融合 SDK 来了!

元宇宙,火得猝不及防。 短短几个月时间,Minecraft、Roblox 进入了更多人的视野,GREE、英伟达、微软等陆续发布相关产品解决方案,韩国、日本还从国家层面宣布大力布局元宇宙赛道。《头号玩家》描绘的情景似乎明天就能成为现实。 &a…

元宇宙与虚拟现实(二)

前言 前面我们关于元宇宙进行了概念上的阐释,本篇文章继续会探讨一些元宇宙里面脑洞大开的话题,如元宇宙和现实的关系,以及热门话题,关于元宇宙怎么炒房~~ 元宇宙不是什么? 1.元宇宙不等于电子游戏 元宇宙大型多人在…

解读元宇宙:映射现实的虚拟平行世界 关注VR AR 区块链Web3.0机会

元宇宙——理想状态是自发无边际的社会体验 。 公众号:领航员kol 阅读我的原创文章: 微博:牛熊领航员kol 阅读我的原创文章: 元宇宙的英文叫做MetaverseMetaverse,是一个映射现实世界的虚拟平行世界,​通…

当Unity实时3D引擎遇上AI虚实交互,Unity要成为元宇宙时代的新引擎

游戏引擎巨头Unity,还在为蔚来、小鹏、理想等14家车厂提供智能座舱等解决方案,以及为香港机场、北京城建、海尔卡奥斯提供数字孪生方案。实时3D引擎,也将是元宇宙时代的核心支撑。 编辑 | 宋慧 出品 | CSDN AI 领域的年度盛会——2022世界人…

万字长文 | ChatGPT的工作原理(一)

ChatGPT 能够自动生成一些读起来表面上甚至像人写的文字的东西,这非常了不起,而且出乎意料。但它是如何做到的?为什么它能发挥作用?我在这里的目的是大致介绍一下 ChatGPT 内部的情况,然后探讨一下为什么它能很好地生成…

手把手教你最近很火的 微信公众号测试号推送消息

最近有很多小伙伴在尝试做消息推送,今天详细教程它来啦!!! 过程不太复杂,跟着一步一步做就可以实现。 没时间的话,先收藏,等有时间了慢慢学! 第一步:注册微信公众号测试…

火狐安装低版本hackbar插件

在火狐安装的最新版hackbar插件无法使用,需要付费的许可证。 可以使用旧版本的HackBar HackBar2.1.3版本下载地址:https://github.com/Mr-xn/hackbar2.1.3 下载最后一个文件。 首先移除之前安装的hackbar,再在浏览器的拓展与主题中手动安装…

火狐浏览器插件汇总(VIP典藏版)

Windows超实用技巧50篇博客(VIP典藏版) 目录 一、进入搜索页面 二、常用插件推荐 1、Adblock Plus 2、OctoTree 3、油猴子 4、video DownloadHelper 5、Screengrab 一、进入搜索页面 位置:设置-附加组件-扩展-寻找更多扩展 二、常用插件推荐 …

渗透测试人员常用的8种火狐插件

目录 1、Max HacKBar 2、FoxyProxy Standard 3、Wappalyzer 4、Shodan 5、User-Agent Switcher and Manager 6、Firefox Multi-Account Containers 7、HTTP Header Live 8、Vulners Web Scanner 如果文章对你有帮助,欢迎关注、点赞、收藏一键三连支持以下哦…

火狐浏览器设置脚本

第一步,打开火狐浏览器,点击如下位置 第二步,进入扩展和主题。 第三步,在搜索框中搜Tampermonkey。 第四步,下载加入拓展,并自动弹出页面。在用户脚本出搜寻你所需要的脚本。

谷歌与火狐Hackbar插件下载与安装

谷歌与火狐Hackbar插件下载与安装 首先下载Hackbar插件:https://github.com/Mr-xn/hackbar2.1.3 将其中的压缩包拖拽到Chrome的扩展程序。 点击详细信息在下面的“来源”处点击一个链接: 会跳转到给插件在Chrome中安装的文件位置,打开hackbar…

火狐浏览器安装AdGuard

火狐浏览器安装AdGuard扩展 由于一些特殊的原因,在国内无法通过火狐扩展商店直接安装AdGuard,在火狐扩展商店虽然能搜索出来 但是我们点击进入之后就会发现如下界面 那到底应该怎么安装呢?我们可以通过以下方法进行安装: 首先通过…