如果项目中有需要后台执行的任务,但是主要的逻辑都在Java代码中,那么我采用的方式是单独建立一个maven模块打成jar包,然后在linux后台通过命令执行Jar包的Main函数:
Shell
java - classpath backtask .jar "net.crazyant.RunWebService"
|
于是就有个前提,得将maven模块打包成jar包,原本很简单的事情,却出现了很多问题。
原始打包方式:使用maven-assembly-plugin
POM配置片段为:
XHTML
<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方法,可以解决这个问题
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/