问题背景,公司一个使用 Spring Boot 的 Mutil 项目,根据 Spring Boot 官方文档配置好 Parent 继承
spring-boot-starter-parent
POM 的时候可以正常编译运行,但是正式上线时,需要切换到继承公司统一的插件集合 Parent POM (这里暂称为:common-plugin,该插件是为了方便执行一些持续集成编译自动化插件,例如maven-deploy-plugin
、maven-docker-plugin
等等插件),然后问题就出现了,编译不通过,类似提示找不到类,找不到符号的错误消息。
我们都知道,根据 Spring Boot 官网文档 中指出,项目需要配置继承 spring-boot-starter-parent
作为父 POM 如下:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.0.2.RELEASEversion>
parent>
.....
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
类似这样子配置,此时执行编译 mvn clean package
是没有问题哒!但是,目前的情况是,我们的项目需要继承自己的 Parent POM(common-plugin
),此时在执行编译,这种方式就行不通啦!因为一个 POM 文件中只能继承一个 Parent。当然肯定有人会说,我们可以把 spring-boot-starter-parent
依赖配置到 common-plugin
里面就可以啦! 首先这种方式是没有问题的,但是考虑到 common-plugin
作为一个公用 POM 自定义插件集合,配置后被公司所有项目组继承使用,且不说会不会出现各种 jar 版本依赖问题, 就 Spring 相关的 jar 版本依赖问题,就比较难处理啦!不能顾此失彼,这种方式成本太高,风险较大。那么该怎么办呢?其实 Spring Boot 官网文档 中给出了解决方案,项目父 POM 配置如下:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.0.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
上边的配置,同样可以起到继承 Parent POM 方式相同的作用,同时解决了多 Parent 不支持的问题。这里要提一点的是,对于 Muti 项目各个子模块中不需要再次配置依赖 spring-boot-dependencies
,只需要继承父项目 POM 即可(这里因为父 POM 已经继承了该依赖,子模块继承传递)。如果在子模块中再次添加了该依赖如下,那么编译会报错。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
dependency>
所以,子模块不需要再次添加该依赖。还要指出的是,父项目继承了 spring-boot-dependencies
依赖后,子模块继承父项目 POM,那么子模块使用到相关依赖的时候,不需要指定 version 版本了。例如子模块配置如下:
<dependencies>
......
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
不需要指定依赖 version,这是因为在 spring-boot-dependencies
POM 中已经定义好了对应的版本,我们可以从 Maven 仓库 pom 文件可以看到这些依赖的版本定义如下:
<dependencies>
......
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<version>2.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
<version>2.0.2.RELEASEversion>
dependency>
dependencies>
好了,到这里基本就能解决由于 Parent POM 依赖导致的编译失败问题,不过,事情并没有结束。在修改完以上配置后,再次编译依旧卡在一个子项目的某个文件上,提示找不到类,找不到符号,错误信息类似如下:
.....
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project bop-service-crm: Compilation failure: Compilation failure:
[ERROR] /Users/wanyang3/git/mutiproject/sub_project_service/src/main/java/com/test/service/modul/impl/ModuleServiceImpl.java:[21,47] 找不到符号
[ERROR] 符号: 类 RestController
[ERROR] 位置: 程序包 org.springframework.web.bind.annotation
[ERROR] /Users/wanyang3/git/mutiproject/sub_project_service/src/main/java/com/test/service/modul/impl/ModuleServiceImpl.java:[47,2] 找不到符号
[ERROR] 符号: 类 RestController
......
What? 从 IDE 中可以看到这个 org.springframework.web.bind.annotation.RestController
是有的呀!尝试注释一下父 POM 中 Parent POM common-plugin
代码依赖,发现执行编译可以通过,说明问题还是出在 common-plugin
中。
仔细观察下,org.springframework.web.bind.annotation.RestController
这个类属于 spring-web 包里面的,然后分别查询一下这两个 Parent POM 中 spring 相关的版本,惊奇的发现,他们都定义了各自的 spring 版本。common-plugin
中定义了
,而 spring-boot-dependencies
Parent POM 中定义了
,而只使用后者时,编译是可以通过的,只使用前者时,编译不通过。那么接下来,我们统一一下 Spring 版本为 4.3.14.RELEASE
,看下是否可以编译通过。
我们采用覆盖 common-plugin
中的 spring.version 方式来完成版本统一,首先放开上边注释的代码,然后在项目父 POM 中配置 spring.version 属性。
<parent>
<artifactId>common-pluginartifactId>
<groupId>com.plugin.commongroupId>
<version>1.1.0version>
parent>
......
<properties>
......
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<java.version>1.8java.version>
<spring.version>4.3.14.RELEASEspring.version>
properties>
这样就可以指定项目使用 4.3.14.RELEASE 版本啦!再次执行编译,发现编译通过啦!!!看来还是版本依赖冲突的问题啊!
参考资料