现状
该项目使用了Maven,并且引入了Spring,包含代码、配置文件、Jar包,使用的是IDEA来作为开发工具,项目的产出物是要打包成一个可运行的Jar包。通过IDEA的打包工具也可以打包成功,只不过需要自己向MANIFEST.MF里面写入Class-Path(引入的Jar包多的时候就比较烦了,或许有简单的方法是我不知道的吧)。鉴于项目使用了Maven,且Maven里面拥有众多优秀的插件,最终决定使用Maven来作为项目的打包工具。
目标
- 自己的代码编译后作为一个主要的启动Jar
- 自己的源代码也打包成为一个Jar
- 引用的Jar包放入到lib目录下
- 需要的配置文件放在conf目录下
- 将我们的启动Jar、lib目录、conf目录打包成一个文件
准备
- 工具
- Maven(必需的)
- IDEA(非必需,看个人习惯)
- Maven插件(核心的)
- maven-compiler-plugin
- maven-jar-plugin
- maven-dependency-plugin
- maven-resources-plugin
- maven-source-plugin
- maven-assembly-plugin
POM详解
基本属性
- <project>
- [...]
- <properties>
- <!--项目使用的JDK版本-->
- <jdk.version>1.8</jdk.version>
- <!--项目使用的Spring版本-->
- <spring.version>4.3.10.RELEASE</spring.version>
- <!--项目文件编码-->
- <sourceEncoding>UTF-8</sourceEncoding>
- </properties>
- [...]
- <dependencies>
- <!--项目的依赖包-->
- [...]
- </dependencies>
- </project>
插件配置
- <project>
- [...]
- <build>
- <plugins>
- <!--我们要使用的插件就在这里-->
- [...]
- </plugins>
- </build>
- [...]
- </project>
maven-compiler-plugin
这个插件是maven在编译项目的时候需要的信息,主要是为其指明JDK版本信息以及编码方式。一般的maven项目初始化后的默认JDK版本是1.5的,如果不注意就会出现莫名其妙的错误。
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.6.2</version>
- <configuration>
- <source>${jdk.version}</source>
- <target>${jdk.version}</target>
- <encoding>${project.build.sourceEncoding}</encoding>
- </configuration>
- </plugin>
maven-jar-plugin
这个插件就是用在打包时,指明必要的信息的,它还有一些其他的定制化的设置可以参考 官方文档
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <!-- 清单文件 -->
- <manifest>
- <!-- 指明我们的项目启动入口,即包含main方法的那个类 -->
- <mainClass>cn.xxx.Abcd</mainClass>
- <!-- 需要增加类的加载路径 -->
- <addClasspath>true</addClasspath>
- <!--
- 类的加载路径,这里的路径是以打包后的jar文件为基准的
- 也就是说这个lib就在打包后的jar所在的那个文件夹下
- -->
- <classpathPrefix>lib/</classpathPrefix>
- </manifest>
- <manifestEntries>
- <!--
- 这里的conf会添加到maven打包时产生的MANIFEST.MF的Class-Path节点中
- 通常的,我们在Spring中的配置文件都是通过classpath来指明位置的,所以这里的说明可以让我们把配置文件拿出来单独放在一起
- -->
- <Class-Path>conf/</Class-Path>
- </manifestEntries>
- </archive>
- </configuration>
- </plugin>
maven-dependency-plugin
这个插件的作用就是把一些依赖包拷贝或者解压到指定的位置去。我们这里仅用了其copy的目标,它的其他目标请参考 官方文档
- <!-- 拷贝依赖的jar包到lib目录 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <id>copy</id>
- <!--绑定到maven的生命周期的package阶段-->
- <phase>package</phase>
- <goals>
- <!--指明我们的目标:拷贝依赖-->
- <goal>copy-dependencies</goal>
- </goals>
- <configuration>
- <!--
- 指明我们拷贝的依赖要放到哪个文件夹下面
- 这里指的是项目的: /项目根目录/target/lib 目录下
- -->
- <outputDirectory>
- ${project.build.directory}/lib
- </outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
maven-resources-plugin
这个主要用来指明资源文件的编码方式了,但是这么插件还有许多其他的功能,具体详情请参考 官方文档
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>2.5</version>
- <configuration>
- <encoding>${project.build.sourceEncoding}</encoding>
- </configuration>
- </plugin>
maven-source-plugin
这个插件用来把我们的源代码也打包成一个Jar文件,这里我们使用其一部分属性,其余属性的使用请参考 官方文档
- <plugin>
- <artifactId>maven-source-plugin</artifactId>
- <version>2.1</version>
- <configuration>
- <!--这里你可以添加一个outputDirectory节点来指明这个文件的输出目录,fileName来指明其输出的名字-->
- <attach>true</attach>
- </configuration>
- <executions>
- <execution>
- <phase>compile</phase>
- <goals>
- <goal>jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
maven-assembly-plugin
好了,怎么打包,前面都做完了,那么这个插件就是来给他们分分类,然后做成一个jar、zip或者tar.gz等等,把我们需要整合到一起的东西给打包到一起。当然,你还可以通过看 官方文档 来进一步了解它。
其实到这一步之前,我们的jar包已经打包完成了,我们的依赖包也都已经拷贝到
下了,同样的,我们的配置文件也已经放到了
- target/lib
下面了,而且我们也已经可以通过
- target/conf
来运行了。所以,这个插件就是用来把这些东西都放在一起,来做最后一步——整合。
- java -jar Abcd.jar
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <version>3.1.0</version>
- <configuration>
- <appendAssemblyId>false</appendAssemblyId>
- <descriptors>
- <!--这个插件需要一个说明器,这里我将它放在src下的assembly目录下-->
- <descriptor>src/assembly/assembly.xml</descriptor>
- </descriptors>
- </configuration>
- <executions>
- <execution>
- <!--这个插件需要绑定到package阶段执行-->
- <phase>package</phase>
- <goals>
- <!--这里是指只执行一次-->
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
然后我们在
如下所示
- assembly.xml
- <assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
- <id>distribution</id>
- <formats>
- <!--最后要输出的文件格式
- 有:zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、tar.snappy、tar.xz (or txz)、jar、dir、war可以选择
- -->
- <format>zip</format>
- <format>tar.gz</format>
- </formats>
- <!--下面就可以看作是分类的过程了-->
- <fileSets>
- <fileSet>
- <!--这里指明我们的源文件所在处-->
- <directory>${basedir}</directory>
- <!--这里指明我们的输出目录-->
- <outputDirectory>\</outputDirectory>
- <!--这里来说明哪些需要包含进来,当然也可以用excludes来说明不包含哪些文件-->
- <includes>
- <include>README*</include>
- <include>LICENSE*</include>
- <include>NOTICE*</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.basedir}\src\script</directory>
- <outputDirectory>\</outputDirectory>
- <includes>
- <include>startup.*</include>
- <include>shutdown.*</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}\lib</directory>
- <outputDirectory>\lib</outputDirectory>
- <includes>
- <include>*.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}</directory>
- <outputDirectory>\</outputDirectory>
- <includes>
- <include>${project.build.finalName}.jar</include>
- </includes>
- </fileSet>
- <fileSet>
- <directory>${project.build.directory}\conf</directory>
- <outputDirectory>\conf</outputDirectory>
- <includes>
- <include>*.properties</include>
- </includes>
- </fileSet>
- </fileSets>
- <dependencySets>
- <dependencySet>
- <!--这里用来指明当打包时我们的依赖文件(*.jar)不要解压,要原封不动的打包进去-->
- <unpack>false</unpack>
- <outputDirectory>\lib</outputDirectory>
- <useProjectArtifact>false</useProjectArtifact>
- <!-- 将scope为runtime的依赖包打包到lib目录下。 -->
- <scope>runtime</scope>
- </dependencySet>
- </dependencySets>
- </assembly>
资源说明
我们还需要说明哪些是我们的资源文件,然后这些会打包进我们的Jar文件里去,而打包进去的资源文件自然地可以以类路径访问了。
- <resources>
- <!-- 控制资源文件的拷贝 -->
- <resource>
- <!--这里来指明那个文件夹是我们的资源文件夹-->
- <directory>src/main/resources</directory>
- <includes>
- <!--来指明需要包含的文件,这里用通配符来表示了,即指在resources下的任意子目录(包括其本身)下的xml和tld文件-->
- <include>**/*.xml</include>
- <include>**/*.tld</include>
- </includes>
- <!--指明这里不需要过滤,注意过滤的文件是不会被打包进去的,就像下面的*.properties文件都不会被打包-->
- <filtering>false</filtering>
- </resource>
- <resource>
- <directory>src/main/resources</directory>
- <includes>
- <include>**/*.properties</include>
- </includes>
- <filtering>true</filtering>
- <!--上面的filter指明这类文件需要过滤出来,那么接下来这个节点说明这类文件还需要输出到/conf目录下-->
- <targetPath>${project.build.directory}/conf</targetPath>
- </resource>
- </resources>
最后
经过以上的步骤之后,我们的项目就算打包完毕了,整个项目目录就是下面这个样子的
- \root
- |``\lib
- | ``\*.jar
- |``\conf
- | ``\*.properties
- |``\Abcd.jar
还有一个跨平台的脚本插件appassembler-maven-plugin,可是我觉得shell这种东西,自己写一写会更好,所以这里仅提供其名字,不提供其用法了。