赞
踩
本文主要介绍我本人在使用maven打包一个普通spring项目使用网上各种教程都没有成功,最后多次尝试分析后成功的过程。
因为平时开发都是开发SSM、SpringBoot这一类web应用,或者为公司开发一些公共组件(导出成jar引入主项目)这样,开发控制台程序也都是使用使用基础的开发模式,建立普通的java项目然后手工导入依赖jar包,最后使用开发工具导出可执行jar包,没有接触过使用maven开发控制台程序导出jar包运行。
根据自己掌握的知识点,肯定是使用maven-jar-plugin插件进行打包操作
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<archive>
<manifest>
<mainClass>org.test.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
执行maven package命令,没报错,去到target目录一看,输出的jar包只有十几K?这明显有问题呀,但是还是使用java -jar执行了一下报错:
很明显项目的依赖包没有被打包出来。于是去百度相关资料…
关于maven如何打包一个普通的spring项目(输出一个执行main方法的jar包),网上很多资料是说使用maven-assembly-plugin这个插件进行打包。
第一次尝试打包使用以下配置:
<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <appendAssemblyId>false</appendAssemblyId> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <!-- 此处指定main方法入口的class --> <mainClass>org.test.App</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>assembly</goal> </goals> </execution> </executions> </plugin>
可以正常打包,但是在执行的时候出现以下错误:
Offending resource: class path resource [*****.xml]
于是百度相关错误,总结下来就是说执行的程序中缺少了Spring一些内置的配置文件,于是使用winRAR打开jar包查看内部的结构,发现所有的依赖jar包全部被解压成一个个class文件:
众所周知,spring内部大部分配置文件都是放在“META-INF”目录下,而且文件名称还是一样的,这些Spring的依赖包被解压后,所有的同名的内置配置文件岂不都相互覆盖了?难怪jar包执行起来报上面那个错误!
于是找到新的方向:怎么使用maven-assembly-plugin插件打包出来的jar包中依赖包不被解压?
查找资料后,发现之前复制网上的pom build配置,是因为使用了maven-assembly-plugin中一个自带的配置文件,而这个配置文件中配置了打包是将所有依赖包解压!
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <archive> <manifest> <mainClass>org.test.App</mainClass> </manifest> </archive> <!-- 这个的意思是依据一个id为“jar-with-dependencies”的配置文件内容来执行打包 <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> --> <descriptors> <!-- 这里的意思是依据指定的配置文件进行打包 --> <descriptor>src/main/resource/assembly/assembly.xml</descriptor> </descriptors> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
jar-with-dependencies执行的默认配置文件内容:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> <id>jar-with-dependencies</id> <formats> <format>jar</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <unpack>true</unpack> <!-- 是否解压依赖jar包 --> <scope>runtime</scope> </dependencySet> </dependencySets> <fileSets> <fileSet> <directory>${project.build.outputDirectory}</directory> </fileSet> </fileSets> </assembly>
自定义配置文件assembly.xml:
<assembly> <id>with-dependence</id><!-- 配置文件的标识,同时生成的jar包名字会把这个文本包含进去 --> <formats> <format>jar</format><!-- 打包类型,此处为jar --> </formats> <includeBaseDirectory>false</includeBaseDirectory> <dependencySets> <dependencySet> <unpack>false</unpack><!-- 是否解压依赖jar包 --> <scope>runtime</scope> </dependencySet> </dependencySets> <fileSets> <fileSet> <directory>${project.build.outputDirectory}</directory> <outputDirectory>/</outputDirectory> </fileSet> </fileSets> </assembly>
执行 maven clean package 命令进行打包,正常执行,输出的jar包也有十几兆了,我以为已经可以了!执行后还是报错:
我打开jar包查看了一下内部的结构,依赖jar包也都在里面:
为什么会执行报错找不到依赖呢?
脑洞了一下,使用SpringBoot的spring-boot-maven-plugin生成可执行jar包会怎么样:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.zc.largecash.cb.removeredis.App</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
导出的可执行jar包,可以正常运行!!!
查看了SpringBoot的spring-boot-maven-plugin生成可执行jar包内部文件结构,
然后再对比以前自己使用myeclipse导出的控制台程序,发现使用maven导出的jar包中“META-INF”下MANIFEST.MF缺少“Class-Path”!
于是手工编辑了MANIFEST.MF文件,将“Class-Path”加上:
Class-Path: ./a1.jar ./a2.jar ./b1.jar .........
执行,发现还是不行,结合MyEclipse导出的控制台程序中的MANIFEST.MF文件:
以及导出的jar包中,出现了一些eclipse的类:
认为应该原生的不支持读取jar包内的依赖jar包的class,于是将依赖jar包复制出来,放置在导出的可执行jar包同级目录,执行正常!
第三次尝试,与第一次使用maven-jar-plugin导出的可执行jar包,执行时出现的错误是一样的,于是回过头查看maven-jar-plugin导出的可执行jar包内的MANIFEST.MF文件,发现也是缺少“Class-Path”这一项参数的
找到maven-jar-plugin与“Class-Path”相关的资料发现:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<mainClass>org.test.App</mainClass>
添加以下2项配置,可以使得导出的可执行jar中MANIFEST.MF文件带有“Class-Path”这一项
<addClasspath>true</addClasspath><!-- true会在MANIFEST.MF加上Class-Path项并配置依赖包 -->
<classpathPrefix>lib/</classpathPrefix><!-- lib/指定依赖包所在目录 -->
</manifest>
</archive>
</configuration>
</plugin>
执行mevan package命令,成功,但是发现2个问题:
以下为MANIFEST.MF文件内容:
查阅相关资料,2个问题都得以解决:
问题1. 使用maven-dependency-plugin插件,可以导出项目依赖jar包到指定目录:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>2.10</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin>
这样一来,maven-jar-plugin配合使用maven-dependency-plugin就可以很好的导出可执行jar包
问题2.
想将配置文件放置在可执行jar包外面,很简单,只需要编辑一下MANIFEST.MF文件中“Class-Path”,添加你配置文件准备放置的位置的相对路径(或者绝对路径,绝对路径应该用的很少),如“ ./ ”则代表可执行jar包同级目录,这样就能将配置文件放在jar包可执行jar包同级目录也能被程序正常读取。
另外需要注意,“Class-Path”配置的值中,会有很多项,各项之间一定要用空格隔开,不能使用其他字符,并且需要确保每一行不能有太多字符,及时换行,每一行最前面需要有空格!
手工编辑MANIFEST.MF文件“Class-Path”值,毕竟还是太繁琐,每次打包都需要操作一遍,目前还没有找到maven-jar-plugin可以配置导出jar包时给MANIFEST.MF文件“Class-Path”值添加自定义信息!希望有大佬来解答一下这个问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。