这个问题简述起来就是项目加载jar包但是无法加载jar包的依赖
这是一个maven的特性吗?
问题发生前
程序猿经常自己写一些库实现或收集常用的逻辑方法(算法和设计模式等等),以方便多个项目使用,避免重复编码。本猿现在有这么一个库,本猿把他叫 E库 , E库用maven做工程和生命周期管理,以便能用到其他java工程中。同时库里面也引用了其他一些开源公共库,使用或包装他们以实现自己的功能。(如下是E库部分依赖截图)
本猿新建一个项目A,并引入这个自用的库,如果项目人多会用私库,多数情况不会超过5个人的,一般本猿会用项目中的文件夹做仓库。在项目A的pom.xml中加入这个文件夹做的仓库:
minimal-maven-repository
file:///${project.basedir}/minimal-maven-repository
default
true
true
这里就用minimal-maven-repository这个文件夹做仓库。
现在,在项目A根目录执行如下命令把E库部署到这个仓库中:
VERSION=1.2.0-snapshot
mvn deploy:deploy-file -Dfile=/server/data/ejoker/target/ejoker-${VERSION}.jar -DgroupId=pro.jiefzz -DartifactId=ejoker -Dversion=${VERSION} -Dpackaging=jar -Durl=file:./minimal-maven-repository/ -DrepositoryId=minimal-maven-repository -DupdateReleaseInfo=true
如果用Nexus私库的话,上面这一步相当于把jar发布到私库,并在项目中引入私库地址。
其中:
选项
用途
-Dfile
指明部署的库的路径
-DgroupId
设置库的groupId
-DartifactId
设置库的唯一artifactId
-Dversion
设置当前要部署库的版本
-Dpackaging
部署的类型
-Durl
仓库的位置,这里用项目里的一个文件夹做仓库
-DrepositoryId
仓库的id,这个选项在部署到中央仓库时有用,这里自便
-DupdateReleaseInfo
(字面意思理解)
如无意外大概会看到如下结果,即代表成功:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building willdelete 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-deploy-plugin:2.7:deploy-file (default-cli) @ willdelete ---
Downloading: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus-utils/1.5.6/plexus-utils-1.5.6.pom
Downloaded: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus-utils/1.5.6/plexus-utils-1.5.6.pom (6 KB at 2.2 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus/1.0.12/plexus-1.0.12.pom
Downloaded: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus/1.0.12/plexus-1.0.12.pom (10 KB at 10.4 KB/sec)
Downloading: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus-utils/1.5.6/plexus-utils-1.5.6.jar
Downloaded: http://maven.aliyun.com/nexus/content/groups/public/org/codehaus/plexus/plexus-utils/1.5.6/plexus-utils-1.5.6.jar (245 KB at 199.1 KB/sec)
Uploading: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.jar
Uploaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.jar (427 KB at 21306.2 KB/sec)
Uploading: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.pom
Uploaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.pom (398 B at 194.3 KB/sec)
Downloading: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml
Uploading: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml
Uploaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml (314 B at 153.3 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.570 s
[INFO] Finished at: 2019-09-26T21:29:43+08:00
[INFO] Final Memory: 8M/99M
[INFO] ------------------------------------------------------------------------
查看下minimal-maven-repository目录看看:
Jiefzzs-MacBook-Pro:willdelete kimffy$ tree minimal-maven-repository/
minimal-maven-repository/
└── pro
└── jiefzz
└── ejoker
├── 1.2.0-snapshot
│ ├── ejoker-1.2.0-snapshot.jar
│ ├── ejoker-1.2.0-snapshot.jar.md5
│ ├── ejoker-1.2.0-snapshot.jar.sha1
│ ├── ejoker-1.2.0-snapshot.pom
│ ├── ejoker-1.2.0-snapshot.pom.md5
│ └── ejoker-1.2.0-snapshot.pom.sha1
├── maven-metadata.xml
├── maven-metadata.xml.md5
└── maven-metadata.xml.sha1
4 directories, 9 files
是不是跟你在别的仓库中看到的结构是一样的啊,仓库就是按这个结构装jar的。
现在,可以在项目A的pom.xml中引入E库以及一些项目中用到的库了:
log4j
log4j
1.2.17
org.slf4j
slf4j-log4j12
1.7.16
pro.jiefzz
ejoker
1.2.0-snapshot
org.apache.httpcomponents
httpclient
4.5.8
接下来,eclipse中
右键点击项目 -> maven -> update project
正常通过没毛病。
接下来在代码中使用项目A的写一段代码,并在里面用上E库:
package pro.jiefzz.willdelete;
import pro.jiefzz.ejoker_support.rocketmq.DefaultMQConsumer;
import pro.jiefzz.ejoker_support.rocketmq.MQInstanceHelper;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
// System.out.println( "Hello World!" );
// 这个其实是E库中创建rocketmq客户端的一个助手类,没什么特别的逻辑的。
DefaultMQConsumer createDefaultMQConsumer = MQInstanceHelper.createDefaultMQConsumer("", "127.0.0.1:9876", null);
}
}
问题发生了
然后运行项目App主类:
鹅?! 找不到类?是本猿打开方式不对吗? 命令中敲一次mvn -Dmaven.test.skip=true clean compile package
-_-! 还真找不到啊。。。
java.lang.NoClassDefFoundError: org/apache/rocketmq/client/consumer/AllocateMessageQueueStrategy
这个明显是rocketmq的,而这个rocketmq的依赖不是E库带着的吗(参考上面的图)?难道本猿还要在项目A的pom.xml中贴一次E库的依赖吗?(其实本猿是故意调用E库中使用有依赖其他jar的代码的😈)
为什么E库的依赖没有被加载到项目A中?
为什么会酱
终端里看一下依赖树 mvn dependency:tree
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ willdelete ---
[INFO] pro.jiefzz:willdelete:jar:0.0.1-SNAPSHOT
[INFO] +- junit:junit:jar:3.8.1:test
[INFO] +- pro.jiefzz:ejoker:jar:1.2.0-snapshot:compile
[INFO] \- org.apache.httpcomponents:httpclient:jar:4.5.10:compile
[INFO] +- org.apache.httpcomponents:httpcore:jar:4.4.12:compile
[INFO] +- commons-logging:commons-logging:jar:1.2:compile
[INFO] \- commons-codec:commons-codec:jar:1.11:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
有点不好看,不要紧 大概就是 willdelete依赖了3个包,其中httpclient 下有3个依赖包,而junit和ejoker就直接是末端,没有更下层的依赖了
eclipse里面看到的是一个意思的。很明显,E库(就是这里的ejoker包)下应该有一些依赖啊(例如rocketmq客户端的,以及前面贴了图的)
这个问题以前就出过,只不过那时没闲管他,直接把E库的依赖往项目A里贴一次(相当于手动提供了😹)
今天刷了很久的Google没找到(以前找过也没找到),找到的都是把依赖的直接跟目标jar打到一起(不管是解压后吧class放到一起还是装到提个lib文件夹里面然后把classpath写到META-INF/mainifest.mf里面,这两殊途同归,行话叫打胖包和打瘦包),都不是本猿要的。
其实问题出在上面那个deploy到本地仓库的过程,
mvn deploy过程里有个参数 -DgeneratePom,默认值是true的 -_-**
那他干了些啥呢?看刚刚那个本地仓库的目录
Jiefzzs-MacBook-Pro:willdelete kimffy$ tree minimal-maven-repository/
minimal-maven-repository/
└── pro
└── jiefzz
└── ejoker
├── 1.2.0-snapshot
│ ├── ejoker-1.2.0-snapshot.jar
│ ├── ejoker-1.2.0-snapshot.jar.md5
│ ├── ejoker-1.2.0-snapshot.jar.sha1
│ ├── ejoker-1.2.0-snapshot.pom
│ ├── ejoker-1.2.0-snapshot.pom.md5
│ └── ejoker-1.2.0-snapshot.pom.sha1
├── maven-metadata.xml
├── maven-metadata.xml.md5
└── maven-metadata.xml.sha1
4 directories, 9 files
看看里面的ejoker-1.2.0-snapshot.pom :
Jiefzzs-MacBook-Pro:willdelete kimffy$ cat minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.pom
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
4.0.0
pro.jiefzz
ejoker
1.2.0-snapshot
Jiefzzs-MacBook-Pro:willdelete kimffy$
这段按人话说就是:这是个包。然后。。 然后没了。 没了?! 是的,没别的了,项目端的maven获得的信息就只有这丁点儿。无语....
他不是E库的pom.xml吧,是那个隐含的-DgeneratePom=true参数的杰作吧...
问题就是这里,maven不知道他还要依赖。一些纯工具类库没有其他依赖的,这样当然不会出问题,他不需要依赖,maven也没为他加载依赖。也有些需要依赖的但是项目中同时又用到了的,似乎没问题,但是只是恰巧遇上刚刚而已,如依赖log类最好理解了 大概率项目也用库里也用。即便有依赖没加载上,回头再打个胖包也是可以的。
但是这不是本猿现在要的。
肿么办才好
既然在仓库里缺了pom.xml那就补上咯,再敲一次命令,其中补上参数-DgeneratePom=false,-Dfile=指向E库的pom.xml,执行如下:
$ mvn deploy:deploy-file -Dfile=/server/data/ejoker/pom.xml -DgroupId=pro.jiefzz -DartifactId=ejoker -Dversion=${VERSION} -Dpackaging=pom -Durl=file:./minimal-maven-repository/ -DrepositoryId=minimal-maven-repository -DupdateReleaseInfo=true -DgeneratePom=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building willdelete 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-deploy-plugin:2.7:deploy-file (default-cli) @ willdelete ---
Uploading: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.pom
Uploaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/1.2.0-snapshot/ejoker-1.2.0-snapshot.pom (7 KB at 354.7 KB/sec)
Downloading: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml
Downloaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml (314 B at 27.9 KB/sec)
Uploading: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml
Uploaded: file:./minimal-maven-repository/pro/jiefzz/ejoker/maven-metadata.xml (314 B at 102.2 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.645 s
[INFO] Finished at: 2019-09-26T22:42:18+08:00
[INFO] Final Memory: 7M/123M
[INFO] ------------------------------------------------------------------------
再看看依赖树:
全部都出来了
再跑一下主类App :
不再是刚刚的错误 而是一个RuntimeException,也就是依赖问题已经被解决,(这个运行时异常是因为本猿在createDefaultMQConsumer的第三个参数传入了null)
再附上一个Nexus私库时如果想最终项目能够继承这个依赖的话应该是这样的,下图红框的位置,同时上送你的jar和项目的pom.xml
有问题欢迎指正😂