SpringCloud+Maven 管理多模块项目遇到的一些问题

环境

项目结构

image.png

Service1 依赖 Common

Service2 依赖 Common

Common 无任何依赖

遇到了什么问题?

mvn package 父项目或 Service 都会报错,也就是说在 maven 多模块结构的项目中,引用了一个没有程序入口的项目将会打包失败

问题分析 + 解决

下面我对两种无法通过打包的情况进行分析,并给出解决方案。

Service 项目无法打包

[ERROR] Failed to execute goal on project Service1: Could not resolve dependencies for project org.ccccye:Service:jar:0.0.1-SNAPSHOT: Could not find artifact org.ccccye:common:jar:0.0.1-SNAPSHOT -> [Help 1]

从异常信息中可以知道两件事

  1. Maven 执行 goal 失败
  2. goal 执行失败是因为 Service1 项目所依赖的 common.jar 包找不到

那么问题根源应该是 Service1 项目找不到 common.jar 包造成的。通过翻阅资料和实验,发现当项目单独打包时,不会主动去编译所依赖的模块项目,而是去本地仓库找 jar 包,如果用 maven install 把 common.jar 安装到本地仓库,是不是能解决问题呢?答案是可以的,在 common 项目执行 mvn install 就可以将 common.jar 安装到本地仓库了,,,等等,这里还会出现另外一个问题,接下来继续讲。

父项目无法打包

[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:repackage (repackage) on project weather-common: Execution repackage of goal org.springframework.boot:spring-boot-maven-plugin:2.1.7.RELEASE:repackage failed: Unable to find main class -> [Help 1]

从异常信息中可以知道两件事

  1. 同样是 Maven 的 goal 执行失败了,并且明确是 repackge 功能,这说明在将普通 jar 重新打包成可执行 jar 的过程中发生了错误
  2. 异常信息中还说了报错原因是找不到 main 函数造成的

因此问题在 main 函数报错上,common 项目根本没有 main 函数并且不需要,这是难为我胖虎啊??翻了资料发现,maven 生成 jar 包的顺序是 先生成普通 jar 包,再包装成可执行 jar(普通 jar 会被覆盖),**注意:**可执行程序肯定要有 main 函数的,那么我们可以通过设置 spring-boot-maven-plugin 插件的 layout 参数,赋值为 NONE,maven 只打包所需的依赖,不扫描 main 函数

<plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <layout>NONE</layout>  <!--让maven不打包可执行jar,不扫描项目的main函数-->
            <classifier>exec</classifier> <!--普通jar和可执行jar不同名,普通jar为xx.jar , 可执行jar为 xx-exec.jar-->
        </configuration>
</plugin>

如上,配置了 layout=NONE 解决了 main 函数问题,在实验过程中发现,Service1 能正常编译,一运行就报异常,提示 找不到或无法加载主类 ,原来 Service 想要的 jar 是一个纯粹的普通 jar 包,虽然设置了 layout=NONE,但 maven 还是会再打包一次,并且会覆盖普通的 jar,让 Service 虽然加载了 jar 包却找不到 jar 包里面所包含的类,在这里我的解决方案是配置普通 jar 跟二次打包的 jar 不同名,也就是配置

<classifier>exec</classifier>

到此,问题的原因和解决方案都有了,这里总结出来的知识点有

  1. 子项目 package 时的依赖是去本地仓库或者远程仓库查找的,不会主动编译本地项目并依赖
  2. Maven 默认会执行 repackge 这个 goal
  3. repackge 将普通 jar 改成 xx.jar.original,可执行 jar 为 xx.jar,可以通过 classifier 参数来修改可执行 jar 的名字后缀
  4. 可执行 jar 默认寻找一个 main 函数,通过配置 layout=none 取消

第二种解决方案

还有一种解决方案,在主项目 pom 更换插件,将 spring-boot-maven-plugin 改为 maven-compiler-plugin,具体的配置为

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
	<source>${java.version}</source>
	<target>${java.version}</target>
</configuration>

然后在主项目运行 package 命令就可以整体编译打包了。不过要打包 Service 子项目的话,Common 项目得手动 install 安装到本地仓库才行。

关联的知识

总结

主 pom 打包方式 service pom common pom
spring-boot-maven-plugin 整体打包 spring-boot-maven-plugin spring-boot-maven-plugin 增加配置:1. layout=none 2.classifier=exec
部分打包 spring-boot-maven-plugin spring-boot-maven-plugin 增加配置:1. layout=none 2.classifier=exec。打包前需要 install
maven-compiler-plugin 整体打包 spring-boot-maven-plugin 无 build 节点
部分打包 spring-boot-maven-plugin 无 build 节点,打包前需要 install

可以看到部分打包都需要提前 install 公共项目,否则 package 过程中找不到 jar 包;使用 maven-compiler-plugin 不需要增加配置。

值得一说的是这两个插件并不是同一个类型的,只是刚好能解决问题,它们的区别如下

这也就不难理解,为什么 spring-boot-maven-plugin 需要增加配置了,因为它不负责编译,只能对编译出来的东西进行打包,因此不能对其他项目进行编译然后打包到 jar 里;maven-compiler-plugin 可以进行编译,在编译阶段能将所依赖的其他项目按顺序编译,最后打包进 jar

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    784 引用 • 1368 回帖 • 694 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    169 引用 • 316 回帖 • 617 关注

赞助商 我要投放

回帖
请输入回帖内容 ...