maven打包的那些事

1. 关于 Maven 打 war 包

使用 Eclipse 的 Maven 2 插件开发一个 JEE 项目》详细介绍了如何在 Eclipse 使用 Maven 新建一个 JEE 项目并对其进行断点跟踪调试,但是没有介绍如何对 JEE 项目打 war 包。其实很简单,你只需要把 pom.xml 中的 <packaging>jar</packaging> 换成 <packaging>war</packaging> 就可以使用 mvn package 命令对其打 war 包了,而不需要添加任何 maven 插件。只要你遵循了 maven 规范(比如照着《使用 Eclipse 的 Maven 2 插件开发一个 JEE 项目》所述做了),那你打成的 war 包就肯定包含了第三方依赖包:
maven打的war包里边的第三方依赖包

把这个 war 包丢进 tomcat 的 webapps 目录,重启 tomcat 即可完成了该项目的部署。你唯一需要注意的是,在重启 tomcat 之前把你的 war 重命名为 项目访问路径.war。比如作者打成的 war 包是为 swifton-1.0.0.war,对该项目定义的访问路径是 /swifton,那么我在重启 tomcat 之前需要将其重命名为 swifton.war。

2. 可执行程序打 jar 包

关于可执行程序(需要指定一个 main 类)打 jar 包就没这么方便了,我们需要考虑以下几个问题:

  • 配置文件需要打进 jar 包;
  • 需要指定 main 入口类;
  • 所依赖的第三方库也要打进 jar 包;

只有同时满足以上三点,我们才可以直接使用 java -jar swiftonrsa-1.0.0.jar 命令成功执行该程序。
为了让讨论不那么抽象,我们在 Eclipse 下新建一个 maven 项目 swiftonrsa:
新建maven项目swiftonrsa

其中,com.defonds.RsaEncryptor 是入口 main 类,其源码如下:

[java]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.defonds;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. import com.defonds.service.LinkPayAntharService;  
  7.   
  8. public class RsaEncryptor {  
  9.   
  10.     public static void main(String[] args) {  
  11.         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  
  12.         LinkPayAntharService linkPayAntharService = (LinkPayAntharService) context.getBean("linkPayAntharService");  
  13.         linkPayAntharService.dealWithYearData();  
  14.     }  
  15. }  

2.1 配置文件打包不需要额外关注

只要你项目所依赖的配置文件都按照 maven 规范放对位置(src/main/resources),那么打好的 jar 包就会把它们一起打包:
配置文件打包不需要额外关注

但是这样打好的 jar 包既没有指定 main 入口类,也没有将依赖包打进来,我们运行它:
swiftonrsa-1.0.0.jar中没有清单属性

提示"swiftonrsa-1.0.0.jar中没有主清单属性",我们查看打好 jar 包下 META-INF 目录中的 MANIFEST.MF,其内容如下:
Manifest-Version: 1.0
Built-By: Defonds
Build-Jdk: 1.7.0_67
Created-By: Apache Maven 3.2.3
Archiver-Version: Plexus Archiver

确实没有指出 main 入口类。

2.2 maven-assembly-plugin 插件

于是我们引入了 maven-assembly-plugin 插件,pom.xml 中加入如下代码:

[html]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <build>  
  2.     <plugins>  
  3.         <plugin>  
  4.             <artifactId>maven-assembly-plugin</artifactId>  
  5.             <configuration>  
  6.                 <appendAssemblyId>false</appendAssemblyId>  
  7.                 <descriptorRefs>  
  8.                     <descriptorRef>jar-with-dependencies</descriptorRef>  
  9.                 </descriptorRefs>  
  10.                 <archive>  
  11.                     <manifest>  
  12.                         <mainClass>com.defonds.RsaEncryptor</mainClass>  
  13.                     </manifest>  
  14.                 </archive>  
  15.             </configuration>  
  16.             <executions>  
  17.                 <execution>  
  18.                     <id>make-assembly</id>  
  19.                     <phase>package</phase>  
  20.                     <goals>  
  21.                         <goal>assembly</goal>  
  22.                     </goals>  
  23.                 </execution>  
  24.             </executions>  
  25.         </plugin>  
  26.     </plugins>  
  27. </build>  


执行 mvn assembly:assembly,成功构建 swiftonrsa-1.0.0.jar,查看其打包目录,各种配置文件以及第三方依赖包也都有:
assembly打包后的目录结构

然后查看 META-INF 目录中的 MANIFEST.MF,内容如下:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: Defonds
Build-Jdk: 1.7.0_67
Main-Class: com.defonds.RsaEncryptor

怀着兴奋的心情执行之:
assembly打包后的执行情况

maven-assembly-plugin 插件没有给我们带来惊喜。错误信息如下:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
原来这是 assembly 插件的一个 bug:http://jira.codehaus.org/browse/MASSEMBLY-360,它在对第三方打包时,对于 META-INF 下的 spring.handlers,spring.schemas 等多个同名文件进行了覆盖,遗漏掉了一些版本的 xsd 本地映射。

2.3 maven-shade-plugin 插件

有破必有立。http://jira.codehaus.org/browse/MASSEMBLY-360 跟帖中有网友推荐了 maven-shade-plugin 插件。于是我们使用 maven-shade-plugin 将 maven-assembly-plugin 替代:

[html]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <build>  
  2.     <plugins>  
  3.         <plugin>  
  4.             <groupId>org.apache.maven.plugins</groupId>  
  5.             <artifactId>maven-shade-plugin</artifactId>  
  6.             <version>1.4</version>  
  7.             <executions>  
  8.                 <execution>  
  9.                     <phase>package</phase>  
  10.                     <goals>  
  11.                         <goal>shade</goal>  
  12.                     </goals>  
  13.                     <configuration>  
  14.                         <transformers>  
  15.                             <transformer  
  16.                                 implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
  17.                                 <mainClass>com.defonds.RsaEncryptor</mainClass>  
  18.                             </transformer>  
  19.                             <transformer  
  20.                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  21.                                 <resource>META-INF/spring.handlers</resource>  
  22.                             </transformer>  
  23.                             <transformer  
  24.                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  25.                                 <resource>META-INF/spring.schemas</resource>  
  26.                             </transformer>  
  27.                         </transformers>  
  28.                     </configuration>  
  29.                 </execution>  
  30.             </executions>  
  31.         </plugin>  
  32.     </plugins>  
  33. </build>  


对于多个第三方包 META-INF 下的同名的 spring.handlers 文件它采取的态度是追加而不是覆盖。执行 maven clean package,成功构建 swiftonrsa-1.0.0.jar,查看其打包目录,各种配置文件以及第三方依赖包也都有,以及 META-INF 目录中的 MANIFEST.MF 的内容,基本如 maven-assembly-plugin 打包后的样子,执行之:
shade插件打包后执行情况

错误信息如下:
java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
这是由于一些包重复引用,打包后的 META-INF 目录多出了一些 *.SF 等文件所致。
有破必有立。博客 http://zhentao-li.blogspot.com/2012/06/maven-shade-plugin-invalid-signature.html 给出了解决方案,pom.xml 添加:

[html]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <configuration>  
  2.   <filters>  
  3.     <filter>  
  4.       <artifact>*:*</artifact>  
  5.       <excludes>  
  6.         <exclude>META-INF/*.SF</exclude>  
  7.         <exclude>META-INF/*.DSA</exclude>  
  8.         <exclude>META-INF/*.RSA</exclude>  
  9.       </excludes>  
  10.     </filter>  
  11.   </filters>  
  12. </configuration>  


于是我们对 maven-shade-plugin 的配置变成这样:

[html]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <build>  
  2.     <plugins>  
  3.         <plugin>  
  4.             <groupId>org.apache.maven.plugins</groupId>  
  5.             <artifactId>maven-shade-plugin</artifactId>  
  6.             <version>1.4</version>  
  7.             <executions>  
  8.                 <execution>  
  9.                     <phase>package</phase>  
  10.                     <goals>  
  11.                         <goal>shade</goal>  
  12.                     </goals>  
  13.                     <configuration>  
  14.                         <filters>  
  15.                             <filter>  
  16.                                 <artifact>*:*</artifact>  
  17.                                 <excludes>  
  18.                                     <exclude>META-INF/*.SF</exclude>  
  19.                                     <exclude>META-INF/*.DSA</exclude>  
  20.                                     <exclude>META-INF/*.RSA</exclude>  
  21.                                 </excludes>  
  22.                             </filter>  
  23.                         </filters>  
  24.                         <transformers>  
  25.                             <transformer  
  26.                                 implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
  27.                                 <mainClass>com.defonds.RsaEncryptor</mainClass>  
  28.                             </transformer>  
  29.                             <transformer  
  30.                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  31.                                 <resource>META-INF/spring.handlers</resource>  
  32.                             </transformer>  
  33.                             <transformer  
  34.                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  35.                                 <resource>META-INF/spring.schemas</resource>  
  36.                             </transformer>  
  37.                         </transformers>  
  38.                     </configuration>  
  39.                 </execution>  
  40.             </executions>  
  41.         </plugin>  
  42.     </plugins>  
  43. </build>  


再次执行 maven clean package,再次执行成功构建后的 swiftonrsa-1.0.0.jar:
再次执行shade插件打包后的swiftonrsa

最后两行是具体业务实现类 com.defonds.service.LinkPayAntharServiceImpl 成功执行打印出的 log 日志。

2.4 示例项目

本文示例项目 swiftonrsa 已上传至 CSDN 资源,有兴趣的朋友可以下载下来参考实验,下载地址:http://download.csdn.net/detail/defonds/8404739
本文示例项目最终 pom.xml 如下:

[html]  view plain  copy
 
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.     <modelVersion>4.0.0</modelVersion>  
  4.   
  5.     <groupId>settle</groupId>  
  6.     <artifactId>swiftonrsa</artifactId>  
  7.     <version>1.0.0</version>  
  8.     <packaging>jar</packaging>  
  9.   
  10.     <name>swiftonrsa</name>  
  11.     <url>http://maven.apache.org</url>  
  12.   
  13.     <properties>  
  14.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15.     </properties>  
  16.   
  17.     <build>  
  18.         <plugins>  
  19.             <plugin>  
  20.                 <groupId>org.apache.maven.plugins</groupId>  
  21.                 <artifactId>maven-shade-plugin</artifactId>  
  22.                 <version>1.4</version>  
  23.                 <executions>  
  24.                     <execution>  
  25.                         <phase>package</phase>  
  26.                         <goals>  
  27.                             <goal>shade</goal>  
  28.                         </goals>  
  29.                         <configuration>  
  30.                             <filters>  
  31.                                 <filter>  
  32.                                     <artifact>*:*</artifact>  
  33.                                     <excludes>  
  34.                                         <exclude>META-INF/*.SF</exclude>  
  35.                                         <exclude>META-INF/*.DSA</exclude>  
  36.                                         <exclude>META-INF/*.RSA</exclude>  
  37.                                     </excludes>  
  38.                                 </filter>  
  39.                             </filters>  
  40.                             <transformers>  
  41.                                 <transformer  
  42.                                     implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">  
  43.                                     <mainClass>com.defonds.RsaEncryptor</mainClass>  
  44.                                 </transformer>  
  45.                                 <transformer  
  46.                                     implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  47.                                     <resource>META-INF/spring.handlers</resource>  
  48.                                 </transformer>  
  49.                                 <transformer  
  50.                                     implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">  
  51.                                     <resource>META-INF/spring.schemas</resource>  
  52.                                 </transformer>  
  53.                             </transformers>  
  54.                         </configuration>  
  55.                     </execution>  
  56.                 </executions>  
  57.             </plugin>  
  58.         </plugins>  
  59.     </build>  
  60.   
  61.   
  62.     <dependencies>  
  63.   
  64.         <!-- logs -->  
  65.         <dependency>  
  66.             <groupId>log4j</groupId>  
  67.             <artifactId>log4j</artifactId>  
  68.             <version>1.2.17</version>  
  69.         </dependency>  
  70.   
  71.         <dependency>  
  72.             <groupId>commons-logging</groupId>  
  73.             <artifactId>commons-logging</artifactId>  
  74.             <version>1.2</version>  
  75.         </dependency>  
  76.   
  77.         <dependency>  
  78.             <groupId>org.slf4j</groupId>  
  79.             <artifactId>slf4j-api</artifactId>  
  80.             <version>1.7.10</version>  
  81.         </dependency>  
  82.   
  83.         <dependency>  
  84.             <groupId>org.slf4j</groupId>  
  85.             <artifactId>slf4j-log4j12</artifactId>  
  86.             <version>1.7.10</version>  
  87.         </dependency>  
  88.   
  89.         <!-- spring -->  
  90.         <dependency>  
  91.             <groupId>org.springframework</groupId>  
  92.             <artifactId>spring-core</artifactId>  
  93.             <version>3.2.3.RELEASE</version>  
  94.         </dependency>  
  95.   
  96.         <dependency>  
  97.             <groupId>org.springframework</groupId>  
  98.             <artifactId>spring-orm</artifactId>  
  99.             <version>3.2.3.RELEASE</version>  
  100.         </dependency>  
  101.   
  102.         <dependency>  
  103.             <groupId>org.springframework</groupId>  
  104.             <artifactId>spring-context</artifactId>  
  105.             <version>3.2.3.RELEASE</version>  
  106.         </dependency>  
  107.   
  108.         <!-- ibatis -->  
  109.         <dependency>  
  110.             <groupId>org.apache.ibatis</groupId>  
  111.             <artifactId>ibatis-sqlmap</artifactId>  
  112.             <version>2.3.4.726</version>  
  113.         </dependency>  
  114.   
  115.         <!-- connector -->  
  116.         <dependency>  
  117.             <groupId>mysql</groupId>  
  118.             <artifactId>mysql-connector-java</artifactId>  
  119.             <version>5.1.19</version>  
  120.         </dependency>  
  121.   
  122.         <!-- dbcp -->  
  123.         <dependency>  
  124.             <groupId>commons-dbcp</groupId>  
  125.             <artifactId>commons-dbcp</artifactId>  
  126.             <version>1.4</version>  
  127.         </dependency>  
  128.   
  129.         <dependency>  
  130.             <groupId>commons-pool</groupId>  
  131.             <artifactId>commons-pool</artifactId>  
  132.             <version>1.6</version>  
  133.         </dependency>  
  134.   
  135.         <!-- rsa encrypt -->  
  136.         <dependency>  
  137.             <groupId>org.bouncycastle</groupId>  
  138.             <artifactId>bcprov-jdk15on</artifactId>  
  139.             <version>1.51</version>  
  140.         </dependency>  
  141.   
  142.         <!-- commons-codec -->  
  143.         <dependency>  
  144.             <groupId>commons-codec</groupId>  
  145.             <artifactId>commons-codec</artifactId>  
  146.             <version>1.6</version>  
  147.         </dependency>  
  148.   
  149.     </dependencies>  
  150. </project>  

猜你喜欢

转载自fengbin2005.iteye.com/blog/2334148