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打包会打包dockerfile吗 maven 打包_spring



把这个 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打包会打包dockerfile吗 maven 打包_spring_02



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


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. new ClassPathXmlApplicationContext("applicationContext.xml");  
12. "linkPayAntharService");  
13.         linkPayAntharService.dealWithYearData();  
14.     }  
15. }


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


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


maven打包会打包dockerfile吗 maven 打包_jar_03



但是这样打好的 jar 包既没有指定 main 入口类,也没有将依赖包打进来,我们运行它:


maven打包会打包dockerfile吗 maven 打包_jar_04



提示"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 中加入如下代码:



    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,查看其打包目录,各种配置文件以及第三方依赖包也都有:


    maven打包会打包dockerfile吗 maven 打包_spring_05



    然后查看 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



    怀着兴奋的心情执行之:


    maven打包会打包dockerfile吗 maven 打包_spring_06



    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 替代:


      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 打包后的样子,执行之:


      maven打包会打包dockerfile吗 maven 打包_maven_07



      错误信息如下:


      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 添加:


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

      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>


      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:


      maven打包会打包dockerfile吗 maven 打包_spring_08


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



      5 .注意:如果你出现以下情况

      E:\workspace\iccardcore\mis\src\main\java\com\hxsmart\sicard\core\webapp\action\
      process\DayEndProcessBean.java:[298,65] 找不到符号

      那么解决方法:

      project---》clean

      然后再执行maven工程----》run as--》maven install

      在对应的target文件夹下就出现相应的包,运行包即可!,一切正常