2.5 模块化迁移策略:从传统项目到模块化系统
模块化迁移策略:从传统项目到模块化系统
将传统 Java 项目迁移至 JDK 9 模块化系统是一项系统性工程,需分阶段实施以降低风险。以下是详细的迁移策略、工具使用和实战示例。
1. 迁移阶段划分
| 阶段 | 目标 | 关键操作 |
|---|---|---|
| 阶段1:兼容性验证 | 确保项目能在 JDK 9 上无模块化运行 | 使用类路径运行,处理废弃 API 和依赖冲突 |
| 阶段2:模块化试点 | 部分代码转为模块,依赖自动模块(非模块化 JAR) | 创建 module-info.java,逐步迁移核心模块 |
| 阶段3:完整模块化 | 全项目模块化,显式管理所有依赖 | 重构模块结构,移除自动模块依赖 |
2. 阶段1:兼容性验证
目标
在不修改代码的情况下,验证项目在 JDK 9 上的运行能力。
关键步骤
-
编译与运行测试
javac -d out -classpath lib/*.jar src/**/*.java java -classpath out:lib/*.jar com.example.Main -
处理兼容性问题
- 废弃 API 检测:
jdeprscan --release 9 myapp.jar - 内部 API 访问:
- 错误示例:
sun.misc.BASE64Encoder不可访问。 - 修复方案:替换为标准 API(
java.util.Base64)。
- 错误示例:
- 废弃 API 检测:
-
依赖冲突排查
- 工具:使用
jdeps分析依赖树:jdeps --class-path lib/*.jar -recursive myapp.jar
- 工具:使用
3. 阶段2:模块化试点
目标
将部分代码转换为模块,依赖未模块化的第三方库作为自动模块。
关键步骤
-
创建初始模块
- 选择核心模块(如
com.utils),添加module-info.java:module com.utils { exports com.utils; requires transitive org.apache.commons.lang3; // 自动模块名:commons.lang3 }
- 选择核心模块(如
-
模块化编译与运行
javac -d out --module-source-path src --module com.utils java --module-path out:lib -m com.utils/com.example.Main -
处理自动模块依赖
- 自动模块命名规则:
- JAR 文件名
log4j-api-2.17.1.jar→ 模块名log4j.api。
- JAR 文件名
- 依赖传递:自动模块默认依赖所有模块,但需显式声明核心 JDK 模块。
- 自动模块命名规则:
4. 阶段3:完整模块化
目标
全项目模块化,显式管理所有依赖(包括第三方库)。
关键步骤
-
重构模块结构
- 模块拆分:按功能拆分模块(如
com.user、com.order)。 - 模块描述符:为每个模块编写
module-info.java。
- 模块拆分:按功能拆分模块(如
-
处理第三方库
- 方案1:等待库官方提供模块化版本(如 Log4j 2.17+)。
- 方案2:手动为库添加模块描述符(生成
module-info.java)。
-
显式依赖管理
module com.myapp { requires java.sql; requires com.utils; requires org.apache.logging.log4j; // 显式声明 Log4j 模块 } -
生成定制化 JRE
jlink --module-path $JAVA_HOME/jmods:mods \ --add-modules com.myapp,java.sql \ --output myapp-runtime
5. 迁移工具链
| 工具 | 用途 | 示例命令 |
|---|---|---|
| jdeps | 分析依赖关系和模块兼容性 | jdeps --generate-module-info ./out myapp.jar |
| jdeprscan | 检测废弃 API 使用 | jdeprscan --release 9 myapp.jar |
| jlink | 生成最小化 JRE | jlink --add-modules java.base... |
| jmod | 创建 JMOD 文件(可选) | jmod create --class-path ... |
6. 常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| 模块依赖未找到 | 检查 requires 声明,确保依赖模块在模块路径中,或添加 --add-modules <模块名>。 |
| 反射访问失败(如 Hibernate) | 使用 opens 开放包权限:opens com.myapp.model to org.hibernate。 |
| 自动模块名冲突 | 重命名 JAR 文件(如 my-lib-1.0.jar → mylib.jar)以生成唯一模块名。 |
| 性能下降 | 检查垃圾回收配置(如 -XX:+UseG1GC),优化模块依赖减少加载时间。 |
7. 迁移最佳实践
- 分阶段实施:
- 先迁移底层工具模块,再逐步向上层业务模块推进。
- 自动化测试:
- 在每个阶段运行单元测试和集成测试(如 JUnit + CI/CD)。
- 依赖管理:
- 优先选择已适配 JDK 9 的第三方库(如 Spring 5、Hibernate 5.3+)。
- 文档与协作:
- 维护模块依赖图和迁移日志,与团队共享知识。
8. 实战示例:迁移 Spring Boot 应用
步骤1:兼容性验证
- 处理问题:
- 替换
javax.xml.bind(JDK 9 中已移除)为第三方实现(如org.glassfish.jaxb)。 - 添加
--add-opens参数开放反射权限:java --add-opens java.base/java.lang=ALL-UNNAMED -jar myapp.jar
- 替换
步骤2:模块化核心组件
- 模块描述符:
module com.myapp.core { requires spring.boot; requires spring.context; opens com.myapp.model to spring.core; // 允许 Spring 反射扫描 }
步骤3:生成定制化 JRE
jlink --module-path $JAVA_HOME/jmods:mods \ --add-modules com.myapp.core,java.sql \ --output springboot-runtime
9. 总结
模块化迁移需结合工具链、分阶段策略和严格测试,核心在于渐进式重构和显式依赖管理。通过模块化,项目将获得更强的封装性、更清晰的架构和更高效的运行时,为后续技术演进(如云原生、微服务)奠定基础。
相关文章:
2.5 模块化迁移策略:从传统项目到模块化系统
模块化迁移策略:从传统项目到模块化系统 将传统 Java 项目迁移至 JDK 9 模块化系统是一项系统性工程,需分阶段实施以降低风险。以下是详细的迁移策略、工具使用和实战示例。 1. 迁移阶段划分 阶段目标关键操作阶段1:兼容性验证确保项目能在…...
java商城解决方案
数字化时代,电子商务已成为企业拓展市场的重要渠道。对于想要建立在线商店的企业来说,选择正确的技术堆栈至关重要。 Java作为一种成熟且广泛使用的编程语言,为构建购物中心提供了强大的功能和灵活性。 商城Java源码:商城开发的核…...
算法-哈希表篇05-四数相加II
四数相加II 力扣题目链接 题目描述 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 解题思路 把数…...
WPS或word接入智能AI
DeepSeek接入WPS 配置WPS (1)下载 OfficeAl助手插件: 插件下载地址:https://www.office-ai.cn/。 安装插件后,打开WPS,菜单栏会新增"OfficeAl助手”选项卡。 如果没有出现, 左上找到文件菜单 -> 选项 ,在…...
Leetcode:学习记录
一、滑动窗口 1. 找出数组中元素和大于给定值的子数组的最小长度 右指针从左到右遍历,在每个右指针下,如果去掉左边元素的元素和大于等于给定值则左指针右移一次,直到小于给定值,右指针右移一个。 2.找到乘积小于给定值的子数组…...
86.在 Vue 3 中使用 OpenLayers 自定义组件(放大、缩小、长度测量、面积测量)
摘要 在 WebGIS 开发中,OpenLayers 是一个非常强大的开源地图库,它可以在 Web 应用中渲染高效的地图。本篇文章将介绍如何在 Vue 3 中使用 OpenLayers,并封装一个自定义地图控件组件,实现地图的放大、缩小、长度测量和面积测量功能…...
http 与 https 的区别?
HTTP(超文本传输协议)和 HTTPS(安全超文本传输协议)是互联网通信的基础协议。随着网络技术的发展和安全需求的提升,HTTPS变得越来越重要。本文将深入探讨HTTP与HTTPS之间的区别,包括其工作原理、安全性、性能、应用场景及未来发展等。 1. HTTP与HTTPS的基本概念 1.1 HT…...
SAIL-RK3576单板运行7b的deepseek对话模型
大概流程: 使用ollama工具进行deepseek的模型部署和使用,先安装ollama工具,在使用ollama工具拉去deepseek模型,最后使用ollama工具加载deepseek模型进行对话...
独立C++ asio库实现的UDP Server
以下是一个使用独立的 C Asio 库实现的 UDP 服务器的示例代码。这个 UDP 服务器可以监听指定端口,接收客户端发送的数据,并将接收到的数据原样返回给客户端。 #include <iostream> #include <asio.hpp> #include <array>class UdpSer…...
SQL Server STUFF 函数的用法及应用场景
在 SQL Server 中,STUFF 函数是一种强大的字符串处理工具,常用于删除指定位置的字符并插入新的字符。通过这个函数,开发者能够灵活地修改字符串,从而在数据处理、字符串拼接和格式化等方面大显身手。本文将深入探讨 STUFF 函数的语…...
MongoDB进阶篇-索引
文章目录 1. 索引概述 2. 索引的类型 2.1 单字段索引 2.2 复合索引 2.3 其他索引 2.3.1 地理空间索引(Geospatial Index) 2.3.2 文本索引(Text Indexes) 2.3.3 哈希索引(Hashed Indexes) 3. 索引相关操作 3.1 查看索引 3.2 创建索引 3.3.1 创建单字段索引 3.3.2 创建复合…...
《机器学习数学基础》补充资料:柯西—施瓦茨不等式以及相关证明
《机器学习数学基础》 153 页,针对图 3-4-3,提出了一个问题:“点 A A A 到 W \mathbb{W} W 上的一个点的距离有无穷多个。现在,我们最关心的是其中最短的那个,怎么找?请参阅 3.6 节。”并且,在…...
VisionPro 划痕检测小练习
划痕检测,我这里用到的是Sobel算子和blob斑点匹配以及blob里面的形态学调整 Sobel 是一种在数字图像处理和计算机视觉领域广泛应用的算法,主要用于边缘检测 脚本展示 #region namespace imports using System; using System.Collections; using System.Drawing; …...
解析 2025 工业边缘计算:三大技术风向的影响力
工业数字化转型的加速,工业边缘计算市场正呈现出蓬勃发展的态势。展望 2025 年,以下三大技术将成为引领工业边缘计算发展的重要风向标。 其一,人工智能与边缘计算的深度融合。人工智能技术将更广泛地应用于工业边缘设备,实现更智…...
企语企业管理系iFair(F23.2_a0)在Debian操作系统中的安装
起因:在安装了F24.8版本后,发现生产用环境和测试、开发用环境还是分开的好。 旧版的用来实验、测试,新版的一步一步小心的配置、使用是比较稳妥的操作。因此,决定在KVM虚拟机上搭建一个F23.2版本的企语系统。 一、 存在的问题 而…...
如何在Flask中处理静态文件
哈喽,大家好,我是木头左! 本文将详细介绍如何在Flask中处理静态文件,包括如何配置静态文件夹、如何访问静态文件以及如何处理静态文件的缓存问题。 配置静态文件夹 在Flask中,你可以通过static_folder参数来指定静态文件夹。默认情况下,Flask会在项目的根目录下寻找名为…...
无人机飞行试验大纲
无人机飞行试验大纲 编制日期:2025年02月11日 一、试验目的与背景 本次无人机飞行试验旨在验证无人机的飞行性能、控制系统稳定性、机体结构强度以及各项任务执行能力。随着无人机技术在各个领域的广泛应用,对其性能进行全面、系统的测试显得…...
C语言初阶牛客网刷题——JZ65 不用加减乘除做加法】【难度:简单】
1. 题目描述 牛客网OJ题链接 写一个函数,求两个整数之和,要求在函数体内不得使用、-、*、/四则运算符号。 2. 分析 十进制相加思想: 157 , 先计算不考虑进位的相加结果 12 (因为 57 的不考虑进位的结果是 2 &#x…...
git 记录
git 记录 报错warning: unknown value given to http.version: 2 报错 warning: unknown value given to http.version: ‘2’ 删除指定http版本 git config --global --unset http.version...
PyTorch Lightning Trainer介绍
PyTorch Lightning 的 Trainer 是框架的核心类,负责自动化训练流程、分布式训练、日志记录、模型保存等复杂操作。通过配置参数即可快速实现高效训练,无需手动编写循环代码。以下是详细介绍和使用示例: Trainer 的核心功能 自动化训练循环 自…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
