Bug的身世之謎
今天又分享一個問題解決的故事。請看下圖框起來的錯誤,明顯就是找不到這個class嘛!
下面我們按照正常人的思路去排查這個問題,既然找不到class那就先看這個依賴的jar包有沒有,如果沒有那就是鐵證如山。
但是事與願違啊,編譯後的lib目錄下真的有這個包o****rder-api-2.0-SNAPSHOT.jar
還是不相信,於是將order-api-2.0-SNAPSHOT.jar解壓了,看看裡面到底有沒有我們需要的class,真的有,此處心情沉重。
一般人到這裡就會懵圈了,但我還年輕啊,腦袋還夠用。接下來看看classpath的配置有沒有問題,如果order-api-2.0-SNAPSHOT.jar不在classpath中,那麼自然就是找不到class啊,機智的我。
於是查看了META-INF/MANIFEST.MF文件,發現裡面依賴的是order-api-2.0-20200225.024541-15.jar,什麼情況,還加上時間戳了。
終於真相大白了,classpath中指向的是order-api-2.0-20200225.024541-15.jar,但lib中只有order-api-2.0-SNAPSHOT.jar。所以找不到class是沒有錯的。
打包配置信息
Maven deploy的時候會自動給快照版本加時間戳,從下圖可以看的出來:
下面來看下目前項目的打包配置,如下:
<code><plugin>
<groupid>org.apache.maven.plugins/<groupid>
<artifactid>maven-jar-plugin/<artifactid>
<version>2.3.1/<version>
<configuration>
<archive>
<manifest>
<mainclass>com.xxx.web.WebApp/<mainclass>
<addclasspath>true/<addclasspath>
<classpathprefix>lib//<classpathprefix>
/<manifest>
/<archive>
/<configuration>
/<plugin>
<plugin>
<groupid>org.apache.maven.plugins/<groupid>
<artifactid>maven-assembly-plugin/<artifactid>
/<plugin>
/<code>
用了assembly插件,對應的配置如下:
assembly.xml
<code><assembly>xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">bin
<formats>
<format>zip/<format>
/<formats>
<includebasedirectory>false/<includebasedirectory>
<dependencysets>
<dependencyset>
<outputdirectory>//<outputdirectory>
<unpack>false/<unpack>
<includes>
<include>${artifact}/<include>
/<includes>
<outputfilenamemapping>xxx-web.jar/<outputfilenamemapping>
/<dependencyset>
<dependencyset>
<outputdirectory>/lib/<outputdirectory>
<useprojectartifact>false/<useprojectartifact>
<unpack>false/<unpack>
/<dependencyset>
/<dependencysets>
/<assembly>
/<code>
打包後目錄中會有一個jar包和一個lib目錄,如下:
<code>-xxx-web.jar
-lib
-xxx.jar
-yyy.jar
/<code>
解決方案
現在需要解決的問題是classpath中的快照依賴和lib目錄中實際的jar包不一致的問題。
主要是兩個插件,所以才會有不一致的情況。
maven-jar-plugin插件中可以加上<useuniqueversions>false/<useuniqueversions>來強制打包時 MANIFEST.MF文件不記錄的Jar時間戳版本。
maven-assembly-plugin插件需要在assembly.xml中進行修改,在dependencySet中增加outputFileNameMapping=${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}
來固定名稱,這樣就可以去掉時間戳了。
下面貼一下修改之後完整的配置:
<code><plugin>
<groupid>org.apache.maven.plugins/<groupid>
<artifactid>maven-jar-plugin/<artifactid>
<version>2.3.1/<version>
<configuration>
<archive>
<manifest>
<mainclass>com.xxx.web.WebApp/<mainclass>
<addclasspath>true/<addclasspath>
<classpathprefix>lib//<classpathprefix>
<useuniqueversions>false/<useuniqueversions>
/<manifest>
/<archive>
/<configuration>
/<plugin>
<plugin>
<groupid>org.apache.maven.plugins/<groupid>
<artifactid>maven-assembly-plugin/<artifactid>
/<plugin>
/<code>
assembly.xml
<code><assembly>xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">bin
<formats>
<format>zip/<format>
/<formats>
<includebasedirectory>false/<includebasedirectory>
<dependencysets>
<dependencyset>
<outputdirectory>//<outputdirectory>
<unpack>false/<unpack>
<includes>
<include>${artifact}/<include>
/<includes>
<outputfilenamemapping>xxx-web.jar/<outputfilenamemapping>
/<dependencyset>
<dependencyset>
<outputfilenamemapping>
${artifact.artifactId}-${artifact.baseVersion}.${artifact.extension}
/<outputfilenamemapping>
<outputdirectory>/lib/<outputdirectory>
<useprojectartifact>false/<useprojectartifact>
<unpack>false/<unpack>
/<dependencyset>
/<dependencysets>
/<assembly>
/<code>
雖然解決了,但感覺還是挺麻煩的。還是spring-boot-maven-plugin插件好用啊,至少沒有出現過這個時間戳的問題,新項目建議大家用spring-boot-maven-plugin插件打包。
關於作者:尹吉歡,簡單的技術愛好者,《Spring Cloud微服務-全棧技術與案例解析》, 《Spring Cloud微服務 入門 實戰與進階》作者, 公眾號 猿天地發起人。
閱讀更多 猿天地 的文章