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 的核心功能 自动化训练循环 自…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...
基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
