IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    将Maven工程打包成可执行JAR包的方法

    Crazyant发表于 2015-11-17 07:57:09
    love 0

    如果项目中有需要后台执行的任务,但是主要的逻辑都在Java代码中,那么我采用的方式是单独建立一个maven模块打成jar包,然后在linux后台通过命令执行Jar包的Main函数:

    java -classpath backtask.jar "net.crazyant.RunWebService"

    于是就有个前提,得将maven模块打包成jar包,原本很简单的事情,却出现了很多问题。

    原始打包方式:使用maven-assembly-plugin

    POM配置片段为:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
            </plugin>   
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2.1</version>
                <configuration>
                    <finalName>mdm-v3-backtasks</finalName>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin> 
        </plugins>
    </build>

    这种打包方式,可以生成/target/mdm-v3-backtasks-1.0.0.2.jar的Jar包,在有些工程中是没有问题的,但是我的新工程打包后,却在运行时出现了如下问题:

    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]
    Offending resource: class path resource [applicationContext-backtasks.xml]
    
            at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
            at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
            at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:318)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1435)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1428)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:195)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243)
            at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
            at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
            at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
            at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
            at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
            at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)

    网上搜了很多文章,发现首先大家都支持的,是maven-assembly-plugin插件,替换成maven-shade-plugin插件。

    但是替换成maven-shade-plugin之后,仍然遇到了很多问题:

    使用maven-shade-plugin逐步解决问题

    使用maven-shade-plugin插件,并没有一下子就把问题解决了,也经过了很多步骤:

    1、修改spring.xml的schema编写方式

    原始的声明是这样的:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd">

    作如下修改,把xsd的版本加上:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    2、引入maven-shade-plugin插件的打包方式遇到的问题

    将原来的maven-assembly-plugin替换成新的打包方式:

    <build>
    	<finalName>mdm-v3-backtasks</finalName>
    	<plugins>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-jar-plugin</artifactId>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-shade-plugin</artifactId>
    			<version>2.4.2</version>
    			<executions>
    				<execution>
    					<phase>package</phase>
    					<goals>
    						<goal>shade</goal>
    					</goals>
    				</execution>
    			</executions>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-resources-plugin</artifactId>
    			<version>2.6</version>
    			<configuration>
    				<encoding>UTF-8</encoding>
    			</configuration>
    		</plugin>
    	</plugins>
    </build>

    然后就报了下面的错:

    Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
            at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:286)
            at sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:239)
            at java.util.jar.JarVerifier.processEntry(JarVerifier.java:317)
            at java.util.jar.JarVerifier.update(JarVerifier.java:228)
            at java.util.jar.JarFile.initializeVerifier(JarFile.java:348)
            at java.util.jar.JarFile.getInputStream(JarFile.java:415)
            at sun.misc.URLClassPath$JarLoader$2.getInputStream(URLClassPath.java:775)
            at sun.misc.Resource.cachedInputStream(Resource.java:77)
            at sun.misc.Resource.getByteBuffer(Resource.java:160)
            at java.net.URLClassLoader.defineClass(URLClassLoader.java:436)
            at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
            at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
            at java.security.AccessController.doPrivileged(Native Method)
            at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
            at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
            at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
            at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)

    在http://zhentao-li.blogspot.com/2012/06/maven-shade-plugin-invalid-signature.html找到了解决方法:

    You need to add the following to pom.xml:
    
            <configuration>
              <filters>
                <filter>
                  <artifact>*:*</artifact>
                  <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                  </excludes>
                </filter>
              </filters>
            </configuration>
    

    于是加入以上的filter,新的POM内容为:

    <build>
    	<finalName>mdm-v3-backtasks</finalName>
    	<plugins>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-jar-plugin</artifactId>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-shade-plugin</artifactId>
    			<version>2.4.2</version>
    			<executions>
    				<execution>
    					<phase>package</phase>
    					<goals>
    						<goal>shade</goal>
    					</goals>
    					<configuration>
    						<filters>
    							<filter>
    								<artifact>*:*</artifact>
    								<excludes>
    									<exclude>META-INF/*.SF</exclude>
    									<exclude>META-INF/*.DSA</exclude>
    									<exclude>META-INF/*.RSA</exclude>
    								</excludes>
    							</filter>
    						</filters>
    					</configuration>
    				</execution>
    			</executions>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-resources-plugin</artifactId>
    			<version>2.6</version>
    			<configuration>
    				<encoding>UTF-8</encoding>
    			</configuration>
    		</plugin>
    	</plugins>
    </build>

    修改后提交,不幸的是,又爆出了下面的错误:

    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]
    Offending resource: class path resource [applicationContext-backtasks.xml]
    
            at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
            at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
            at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:80)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:318)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1435)
            at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1428)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:195)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139)
            at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
            at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
            at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:243)
            at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:127)
            at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:93)
            at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
            at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537)
            at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451)
            at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
            at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)

    最后在http://robert-reiz.com/2011/11/14/832/页面找到了答案:

    这是因为项目中包含了很多的Spring Jar,不同的Spring Jar会有相同的文件名称,他们相互冲突,为了避免元数据文件的相互覆盖,应该合并他们,如果使用maven shade plugin的话,可以在POM中加上下面的信息来解决:

    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
      <resource>META-INF/spring.handlers</resource>
    </transformer>
    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
      <resource>META-INF/spring.schemas</resource>
    </transformer>
    

    对该问题,官方的解释位于:http://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html

    在“Merging Content of Specific Files with AppendingTransformer and XmlAppendingTransformer”小节,解释为:

    很多的JAR包含了相同的文件名称,为了避免相互覆盖,可以将他们合并到单个文件中。一个很好的例子,就是spring-context包和plexus-spring包,他俩都有META-INF/spring.handlers文件,这个文件被Spring用来处理XML Schema namespaces,通过如下所示的merge方法,可以解决这个问题

    问题终于找到了,原来在这里,看下官方贴出来的POM:

    <project>
      ...
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.2</version>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>shade</goal>
                </goals>
                <configuration>
                  <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                      <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                      <resource>META-INF/spring.schemas</resource>
                    </transformer>
                  </transformers>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
      ...
    </project>
    

    最终的解决方案

    最终的POM文件如下所示:

    <build>
    	<finalName>mdm-v3-backtasks</finalName>
    	<plugins>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-jar-plugin</artifactId>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-shade-plugin</artifactId>
    			<version>2.4.2</version>
    			<executions>
    				<execution>
    					<phase>package</phase>
    					<goals>
    						<goal>shade</goal>
    					</goals>
    					<configuration>
    						<transformers>
    							<transformer
    								implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
    								<resource>META-INF/spring.handlers</resource>
    							</transformer>
    							<transformer
    								implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
    								<resource>META-INF/spring.schemas</resource>
    							</transformer>
    						</transformers>
    						<filters>
    							<filter>
    								<artifact>*:*</artifact>
    								<excludes>
    									<exclude>META-INF/*.SF</exclude>
    									<exclude>META-INF/*.DSA</exclude>
    									<exclude>META-INF/*.RSA</exclude>
    								</excludes>
    							</filter>
    						</filters>
    					</configuration>
    				</execution>
    			</executions>
    		</plugin>
    		<plugin>
    			<groupId>org.apache.maven.plugins</groupId>
    			<artifactId>maven-resources-plugin</artifactId>
    			<version>2.6</version>
    			<configuration>
    				<encoding>UTF-8</encoding>
    			</configuration>
    		</plugin>
    	</plugins>
    </build>

    使用本POM配置,打包、运行均成功没有出错。

    参考链接:

    官方:http://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html

    安全问题:http://zhentao-li.blogspot.com/2012/06/maven-shade-plugin-invalid-signature.html

    Context问题:http://robert-reiz.com/2011/11/14/832/

     

    本文地址:http://www.crazyant.net/1886.html,转载请注明来源

     

    您可能也喜欢:

    python执行shell的两种方法

    将普通Maven Spring项目转换成Web项目的方法

    MySQL执行Select语句将结果导出到文件的方法

    PHP数组使用、特性、函数的总结

    有句话说的非常好
    无觅


沪ICP备19023445号-2号
友情链接