模块构建方式是否影响同名Java类的选用?Maven场景问询
Maven多模块依赖下同名类的调用问题及解决方案
核心问题答案
默认情况下不会调用对应版本的类,原因如下:
- 如果模块1和模块2的GAV(groupId:artifactId:version)完全一致,Maven会判定为同一依赖,只会引入其中一个JAR,导致模块3、4共用同一个
a.b.ClassWithSameName; - 即使模块1和模块2的GAV不同,Maven会将两者都引入类路径,但Java类加载器遵循"先到先得"规则,加载类路径中第一个找到的
a.b.ClassWithSameName,模块3、4的调用都会指向这个类,而非各自依赖的版本。
确保调用正确版本的解决方案
1. 启用Java模块系统(JPMS)
通过显式模块声明实现类隔离,给每个模块添加module-info.java:
- 模块1的
module-info.java:module module1 { exports a.b; } - 模块2的
module-info.java:module module2 { exports a.b; } - 模块3的
module-info.java:module module3 { requires module1; } - 模块4的
module-info.java:module module4 { requires module2; } - 模块5的
module-info.java:module module5 { requires module3; requires module4; }
JPMS会强制模块间的依赖隔离,模块3只会加载模块1的a.b.ClassWithSameName,模块4只会加载模块2的版本,彻底避免冲突。
2. 使用Maven Shade插件重命名包
通过重命名冲突包从根源消除类名重复,比如给模块1配置Shade插件,将a.b包重命名为a.b.module1:
在模块1的pom.xml中添加:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>a.b</pattern> <shadedPattern>a.b.module1</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build>
之后模块3中调整代码调用a.b.module1.ClassWithSameName,模块4仍调用a.b.ClassWithSameName,两者完全隔离,不会冲突。
3. 容器层面类加载隔离(仅适用于Web应用)
如果是Web项目,可在容器中配置类加载器隔离(比如Tomcat给不同WAR包设置独立类加载器),但此方案依赖容器特性,通用性较差,优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者tm1701
相关产品推荐
相关产品推荐

