如何使用Maven“shade”插件将Apache CXF应用程序打包到单片JAR中

我正在编写一个基于控制台的Java应用程序,旨在由cron以批处理方式运行。 批处理应用程序使用Apache CXF框架为JAX-WS调用SOAP Web服务。

为了简化部署并防止CLASSPATH问题,我想将应用程序(及其所有依赖项)捆绑到一个单一的JAR文件中…使用Maven的“shade”插件 。

当我从Eclipse工作区运行它时,我的应用程序工作正常。 但是,当我尝试执行着色的JAR文件时,我得到一个堆栈跟踪,如下所示:

 org.apache.cxf.service.factory.ServiceConstructionException: Could not resolve a binding for null at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createBindingInfo(AbstractWSDLBasedEndpointFactory.java:404) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpointInfo(AbstractWSDLBasedEndpointFactory.java:258) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:146) at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:52) at org.apache.cxf.frontend.ClientProxyFactoryBean.create(ClientProxyFactoryBean.java:102) at org.apache.cxf.jaxws.JaxWsProxyFactoryBean.create(JaxWsProxyFactoryBean.java:115) at com.example.gui.domain.Session.getService(Session.java:145) at com.example.gui.domain.service.soap.AbstractServiceImpl.(AbstractServiceImpl.java:23) at com.example.gui.domain.service.soap.GetUserConsoleOrgsImpl.(GetUserConsoleOrgsImpl.java:14) at com.example.gui.domain.service.ServiceFactory.getGetUserConsoleOrgsService(ServiceFactory.java:443) at com.example.gui.domain.AccessManager.getOrgs(AccessManager.java:62) at com.example.gui.windows.ConsoleApplet.login (ConsoleApplet.java:1253) at com.example.gui.windows.ConsoleApplet.init(ConsoleApplet.java:1227) at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: org.apache.cxf.BusException: No binding factory for namespace http://schemas.xmlsoap.org/soap/ registered. at org.apache.cxf.binding.BindingFactoryManagerImpl.getBindingFactory(BindingFactoryManagerImpl.java:91) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createBindingInfo(AbstractWSDLBasedEndpointFactory.java:394) ... 14 more java.lang.NullPointerException at com.example.gui.domain.service.soap.GetUserConsoleOrgsImpl.getUserConsoleOrgs(GetUserConsoleOrgsImpl.java:29) at com.example.gui.domain.AccessManager.getOrgs(AccessManager.java:64) at com.example.gui.windows.ConsoleApplet.login (ConsoleApplet.java:1253) at com.example.gui.windows.ConsoleApplet.init(ConsoleApplet.java:1227) at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source) at java.lang.Thread.run(Unknown Source) 

事实上,如果你查看这个讨论板消息 ,我遇到的问题与这个人有完全相同。 正如另一个人在那个post中指出的那样,我的问题可能在于Maven“shade”插件。

Apache CXF由许多JAR文件依赖项组成,显然这些JAR中不止一个依赖于其META-INF目录中的内容。 Maven“shade”插件显然将所有这些META-INF目录折叠成一个,并覆盖必要的文件而不是将它们合并在一起。

该讨论主题中的某个人提供了这个Maven POM文件的链接,显示有配置选项和变换器,用于使“shade”插件正确合并这些CXF依赖项。 我将这些设置插入到我自己的POM中,如下所示:

  org.apache.maven.plugins maven-shade-plugin 1.4   package  shade     com.example.MainClass   Apache CXF   META-INF/spring.handlers   META-INF/services/com.sun.tools.xjc.Plugin   META-INF/spring.schemas   META-INF/cxf/cxf.extension   META-INF/extensions.xml   META-INF/cxf/extensions.xml   META-INF/cxf/bus-extensions.txt   META-INF/cxf/bus-extensions.xml   META-INF/wsdl.plugin.xml   META-INF/tools.service.validator.xml   META-INF/tools-plugin.xml   META-INF/cxf/java2wsbeans.xml        

但是,我找不到任何关于这些设置正在做什么的真实解释…并且在启用调试输出的情况下运行Maven时出现以下错误:

 [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1:14.357s [INFO] Finished at: Tue Jul 26 11:10:43 EDT 2011 [INFO] Final Memory: 18M/59M [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:1.4:shade (default) on project salestax-poster: Unable to parse configuration of mojo org.apache.maven.plugins:maven-shade-plugin:1.4:shade: ClassNotFoundException: Class name which was explicitly given in configuration using 'implementation' attribute: 'org.apache.cxf.maven.PluginTransformer' cannot be loaded -> [Help 1] org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:1.4:shade (default) on project salestax-poster: Unable to parse configuration of mojo org.apache.maven.plugins:maven-shade-plugin:1.4:shade: ClassNotFoundException: Class name which was explicitly given in configuration using 'implementation' attribute: 'org.apache.cxf.maven.PluginTransformer' cannot be loaded at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:221) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59) ... 

它似乎抱怨它找不到org.apache.cxf.maven.PluginTransformer类,它似乎存在于cxf-buildtools包中。 但是,当我将该包添加到POM的依赖项时,我在构建过程中又出现了另一个错误:

 Jul 26, 2011 10:44:02 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31: display name [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]; startup date [Tue Jul 26 10:44:02 EDT 2011]; root of context hierarchy Jul 26, 2011 10:44:02 AM org.apache.cxf.bus.spring.BusApplicationContext getConfigResources INFO: No cxf.xml configuration file detected, relying on defaults. Jul 26, 2011 10:44:02 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory INFO: Bean factory for application context [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]: org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26 Jul 26, 2011 10:44:02 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26: defining beans [cxf,org.apache.cxf.bus.spring.BusApplicationListener,org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor,org.apache.cxf.bus.spring.Jsr250BeanPostProcessor,org.apache.cxf.bus.spring.BusExtensionPostProcessor,org.apache.cxf.resource.ResourceManager,org.apache.cxf.configuration.Configurer,org.apache.cxf.binding.BindingFactoryManager,org.apache.cxf.transport.DestinationFactoryManager,org.apache.cxf.transport.ConduitInitiatorManager,org.apache.cxf.wsdl.WSDLManager,org.apache.cxf.phase.PhaseManager,org.apache.cxf.workqueue.WorkQueueManager,org.apache.cxf.buslifecycle.BusLifeCycleManager,org.apache.cxf.endpoint.ServerRegistry,org.apache.cxf.endpoint.ServerLifeCycleManager,org.apache.cxf.endpoint.ClientLifeCycleManager,org.apache.cxf.transports.http.QueryHandlerRegistry,org.apache.cxf.endpoint.EndpointResolverRegistry,org.apache.cxf.headers.HeaderManager,org.apache.cxf.catalog.OASISCatalogManager,org.apache.cxf.endpoint.ServiceContractResolverRegistry]; root of factory hierarchy [DEBUG] java.lang.AbstractMethodError: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; at org.apache.cxf.tools.validator.internal.Stax2DOM.startElement(Stax2DOM.java:173) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:135) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:95) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:76) at org.apache.cxf.tools.validator.internal.WSDL11Validator.getWSDLDoc(WSDL11Validator.java:91) at org.apache.cxf.tools.validator.internal.WSDL11Validator.isValid(WSDL11Validator.java:111) at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:201) at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:61) at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:132) at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:238) at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:83) at org.apache.cxf.tools.wsdlto.WSDLToJava.run(WSDLToJava.java:103) at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:360) at org.apache.cxf.maven_plugin.WSDL2JavaMojo.execute(WSDL2JavaMojo.java:257) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59) at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156) at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537) at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196) at org.apache.maven.cli.MavenCli.main(MavenCli.java:141) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409) at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352) Jul 26, 2011 10:44:03 AM org.springframework.context.support.AbstractApplicationContext doClose INFO: Closing org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31: display name [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]; startup date [Tue Jul 26 10:44:02 EDT 2011]; root of context hierarchy Jul 26, 2011 10:44:03 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26: defining beans [cxf,org.apache.cxf.bus.spring.BusApplicationListener,org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor,org.apache.cxf.bus.spring.Jsr250BeanPostProcessor,org.apache.cxf.bus.spring.BusExtensionPostProcessor,org.apache.cxf.resource.ResourceManager,org.apache.cxf.configuration.Configurer,org.apache.cxf.binding.BindingFactoryManager,org.apache.cxf.transport.DestinationFactoryManager,org.apache.cxf.transport.ConduitInitiatorManager,org.apache.cxf.wsdl.WSDLManager,org.apache.cxf.phase.PhaseManager,org.apache.cxf.workqueue.WorkQueueManager,org.apache.cxf.buslifecycle.BusLifeCycleManager,org.apache.cxf.endpoint.ServerRegistry,org.apache.cxf.endpoint.ServerLifeCycleManager,org.apache.cxf.endpoint.ClientLifeCycleManager,org.apache.cxf.transports.http.QueryHandlerRegistry,org.apache.cxf.endpoint.EndpointResolverRegistry,org.apache.cxf.headers.HeaderManager,org.apache.cxf.catalog.OASISCatalogManager,org.apache.cxf.endpoint.ServiceContractResolverRegistry]; root of factory hierarchy [INFO] ------------------------------------------------------------------------ [INFO] BUILD FAILURE [INFO] ------------------------------------------------------------------------ [INFO] Total time: 8.152s [INFO] Finished at: Tue Jul 26 10:44:03 EDT 2011 [INFO] Final Memory: 10M/59M [INFO] ------------------------------------------------------------------------ [ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.2:wsdl2java (generate-sources) on project salestax-poster: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; -> [Help 1] org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.2:wsdl2java (generate-sources) on project salestax-poster: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:217) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84) at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59) at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183) at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156) at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537) at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196) at org.apache.maven.cli.MavenCli.main(MavenCli.java:141) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409) at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352) Caused by: org.apache.maven.plugin.MojoExecutionException: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:363) at org.apache.cxf.maven_plugin.WSDL2JavaMojo.execute(WSDL2JavaMojo.java:257) at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101) at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209) ... 19 more Caused by: java.lang.AbstractMethodError: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; at org.apache.cxf.tools.validator.internal.Stax2DOM.startElement(Stax2DOM.java:173) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:135) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:95) at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:76) at org.apache.cxf.tools.validator.internal.WSDL11Validator.getWSDLDoc(WSDL11Validator.java:91) at org.apache.cxf.tools.validator.internal.WSDL11Validator.isValid(WSDL11Validator.java:111) at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:201) at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:61) at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:132) at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:238) at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:83) at org.apache.cxf.tools.wsdlto.WSDLToJava.run(WSDLToJava.java:103) at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:360) ... 22 more 

有没有人在Maven着色JAR的上下文中使用过Apache CXF,并且可以提供一些关于如何正常工作的指导?

解决方案是将cxf-buildtools的依赖项添加到插件元素。

  org.apache.maven.plugins maven-shade-plugin 1.4   package  shade     ## you name class name ##   META-INF/spring.handlers   META-INF/spring.schemas   META-INF/services/com.sun.tools.xjc.Plugin   META-INF/cxf/cxf.extension   META-INF/extensions.xml   META-INF/cxf/extensions.xml   META-INF/cxf/bus-extensions.txt   META-INF/cxf/bus-extensions.xml   META-INF/wsdl.plugin.xml   META-INF/tools.service.validator.xml   META-INF/tools-plugin.xml   META-INF/cxf/java2wsbeans.xml    true executable      org.apache.cxf cxf-buildtools 2.2.12 jar compile    

在我的情况下,我只需要添加:

  META-INF/cxf/bus-extensions.txt  

如果你看一下这个带有和没有变压器标签的文件,那么就会有很大的不同(只有一行与~50行),特别是行:

 org.apache.cxf.binding.soap.SoapBindingFactory::true org.apache.cxf.binding.soap.SoapTransportFactory::true 

我不相信这是导致问题的原因。

我或多或少地解决了这个问题。

Maven“shade”插件带有“变换器”的概念,它使您能够在单片JAR中将冲突文件合并在一起而不是覆盖另一个。 有不同类型的变压器……最常见的是:

  • org.apache.maven.plugins.shade.resource.AppendingTransformer – 只需将一个文本文件附加到另一个文本文件的末尾
  • org.apache.maven.plugins.shade.resource.XmlAppendingTransformer – 将XML附加在一起,同时保持格式清晰

在我上面的POM片段中,我从该讨论板线程中提供的示例中获取了一个变换器列表。 它包括两个变形金刚,它们不是开箱即用的默认“阴影”插件的一部分:

  • org.apache.cxf.maven.PluginTransformer
  • org.apache.cxf.maven.CXFAllTransformer

显然,这两个是特定于CXF的附加组件,不附带“阴影”插件,但必须由CXF JAR单独提供。

我的“解决方案”是不完整的,因为我无法弄清楚如何获得这些依赖关系。 它们似乎是cxf-buildtools Maven依赖包的一部分……但是正如上面的问题文档,无论我如何尝试将该依赖项插入到我的POM中,我都遇到了问题。

然而,实际上我的解决方案是简单地从“阴影”插件配置中完全删除这两个变换器。 没有它们,我的阴影JAR应用程序完美无缺。 也许这两个特定的变换器在特殊边缘情况下起作用,但对于vanilla CXF服务调用,似乎可以省略它们。

仅供记录,如果您使用带有cxf和shade插件的camel,请不要忘记“转换”文件META-INF / services / org / apache / camel / TypeConverterTypeConverter。 (3个小时丢失)

  META-INF/services/org/apache/camel/TypeConverter  

除了之前的回复,只是说为了使用对应于项目中包含的依赖项的对象JAXBContext (在我的例子中是jaxb-impl-2.2.11.jar),还需要连接META-INF /services/javax.xml.bind.JAXBContext就好

case PathList(“META-INF”,“services”,“javax.xml.bind.JAXBContext”,xs @ _ *)=> MergeStrategy.concat

在SBT中,或在Maven中的等价物。

否则,使用的JAXBContext将是JVM的,在我的例子中,我得到了这个

创建了JAXBContext“jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/rt.jar!/ com / sun / xml / internal / bind / v2 / runtime / JAXBContextImpl。 class Build-Id:1.8.0_45

我这样解决了它:

基本上cxf库都提供META-INF / cxf / bus-extensions.txt文件,打包器的默认行为是替换该文件,导致它不完整。 通过配置着色器来追加而不是替换cxf东西会表现正常。

将其添加到插件部分中pom的构建部分:

   org.apache.maven.plugins maven-shade-plugin 1.4  true    package  shade     META-INF/cxf/bus-extensions.txt     *:*  META-INF/*.SF META-INF/*.DSA META-INF/*.RSA