在开发中,无论是在微服务架构下还是单体架构下,我们经常使用到多模块开发,其中必然有抽取公共模块,将重复的依赖和重复的工具类整合的一个过程。

        但在我们打包时,我们经常会莫名其妙地出现can't find sympol的问题。明明在java类的import语句中正常导入了正确路径的类,也没有爆红,为什么会找不到类呢?这主要是由于我们在对common模块打包时jar包的属性以及结构导致的原因。

1.首先我们要理解maven工程是如何调用我们在pom.xml文件中声明的依赖的。

当我们编译maven项目时,maven工程会去我们本地仓库,根据坐标找到对应的jar包,然后将其复制到本包下的BOOT-INF/libs下,如图:

maven项目怎么添加启动类启动_jar包

 我们在本项目中引入了springboot框架的web模块,那我们来到本地maven仓库:

maven项目怎么添加启动类启动_可执行_02

 

maven项目怎么添加启动类启动_maven_03

maven项目怎么添加启动类启动_java_04

  

maven项目怎么添加启动类启动_可执行_05

 

maven项目怎么添加启动类启动_可执行_06

 

maven项目怎么添加启动类启动_maven项目怎么添加启动类启动_07

 可以得知,groupId,artifactId,version三者由高到低组成了maven寻找依赖对应jar包的整个路径,其中这些内容都是在我们导入依赖的时候从中心仓库下载得来。

而我们项目中只要引入了dependency依赖,我们就会根据坐标找到对应jar包,复制到本包下。那我们java类又是如何导入jar包的类呢?

2.我们要了解一个普通JAR包的基本内容

以Netflix-Eureka为例

maven项目怎么添加启动类启动_jar包_08

 我们可以看到其具体结构如下:

maven项目怎么添加启动类启动_java_09

 1)其中META-INF存放本jar包的配置信息,如pom.xml,pom.properties等:

maven项目怎么添加启动类启动_jar包_10

 2)org则是其工程下的一个jar子包,其最底层才是我们想要使用的java类:

maven项目怎么添加启动类启动_maven项目怎么添加启动类启动_11

3)那么我们在java文件中导包的过程,实际上就是导入其类所在的路径: 

maven项目怎么添加启动类启动_maven项目怎么添加启动类启动_12

 这个了解之后,我们就知道我们在项目中如何进行导包的了,距离解决我们的问题也接近了。

3.然后,我们要了解spring-boot打成的我们项目可执行jar包的结构

maven项目怎么添加启动类启动_java_13

 使用7-ZIP打开可以清楚看到,我们的可执行JAR包中主要由两个文件夹,一个是BOOT-INF,一个是META-INF。

上面我们说到,META-INF文件夹是存放一些配置,org则是本文件夹下的一部分jar包。那么我们如何运行这个可执行jar包的呢?可执行jar包和普通jar包的区别在何处呢?

就在BOOT-INF

1)如何启动可执行jar包的

首先我们先查看一下BOOT-INF,其下的结构是这样:

maven项目怎么添加启动类启动_java_14

我们点进去后会发现,我们编写的代码在classes文件夹下,我们的主启动程序也在其之下:

maven项目怎么添加启动类启动_java_15

maven项目怎么添加启动类启动_maven项目怎么添加启动类启动_16

maven项目怎么添加启动类启动_maven_17

 

 

看到这里大家应该能把jar包内容和项目结构完全对应(resources文件夹本质上就是根文件夹,其下的内容就在根路径下,这也是为什么比如mybatis对应的xml文件路径配置前通常我们会加上"classpath:"的原因)

 所以启动可执行jar包的过程,本质上就是我们去BOOT-INF/classes/去启动我们主启动类的过程。

2)libs文件夹下则存放着我们我们找到的依赖:即标题1中找到的jar包,将其复制到了这里

maven项目怎么添加启动类启动_java_18

 到这里,我们基本摸清了maven的整个流程,可以解决我们的问题了。

4.为什么我们在IDEA里面明明没有报错,使用mvn compile命令后,却找不到类呢?

直接上答案:因为你把common模块打成了可执行jar包,其具有BOOT-INF文件夹。

那达成可执行jar包为什么会影响我调用common模块下的类呢?

因为我们调用Jar包默认都是在jar包根路径下调用:

再把图贴出来方便大家看:

maven项目怎么添加启动类启动_java_09

而一旦我们把项目达成可执行jar包,在标题3中我们讲的,我们项目内的类就会在BOOT-INF/classes下:

maven项目怎么添加启动类启动_maven项目怎么添加启动类启动_20

所以此时,我们common模块的类并没有在jar包根目录下,而是在BOOT-INF/classes下。

但是我们java导包默认地是去包的根路径下,而根路径此时啥都没有:

maven项目怎么添加启动类启动_maven_21

 所以就找不到当前类

5.那如何解决java寻找jar包类的寻找过程问题呢?

很简单哇,将common模块变成普通jar包,没有BOOT-INF,其内容都在jar包根路径下不就能过正常找到类了吗?

工作:替换common模块的pom.xml下的打包插件,将spring-boot-maven-plugin下添加一行配置:

maven项目怎么添加启动类启动_java_22

 skip标签就能跳过BOOT-INF的打包过程,执行完后:

1)先install common包

2)更新全部依赖

最后我们的结构是这样的:

消费者模块中引入了common模块:

maven项目怎么添加启动类启动_可执行_23

我们的common jar包,就理所应当应该在BOOT-INF/libs/下,我们去仓库寻找:

maven项目怎么添加启动类启动_java_24

 打开后,我们发现,此时common模块没有了BOOT-INT文件夹,其原本所有的类均在其子路径下:

maven项目怎么添加启动类启动_jar包_25

 

二者对应:这是jar包的结构

maven项目怎么添加启动类启动_可执行_26

 这是我们项目的结构

 

maven项目怎么添加启动类启动_可执行_27

 我们就可以成功一一对应!

到此结束!