使用Maven和Jetty创建可执行的JAR文件

5

我想使用Jetty启动我的应用程序,因此我已经添加了下面提到的依赖项。当我运行主方法时,Jetty成功启动。(我正在开发一个struts2+spring3+hibernate maven项目,我也可以在tomcat中部署它)

现在我想从war打包的pom文件中创建可执行的jar文件。所以我在我的pom中添加了maven-assembly-plugin。(我尝试过maven jar插件,但它没有添加依赖项)

来源

插件

<build>
    <plugins>
        <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.3</version>
        <configuration>
                 <archive>
            <manifest>
        <mainClass>com.dca.engine.StartDCA</mainClass>
            </manifest>
             </archive>
        <packagingExcludes>WEB-INF/lib/jetty*.jar,WEB-INF/lib/org.apache.taglibs.standard.glassfish*.jar,WEB-INF/lib/org.apache.jasper.glassfish*.jar,WEB-INF/lib/org.eclipse.jdt.core*.jar,WEB-INF/lib/javax.servlet.jsp*.jar,WEB-INF/lib/javax.el*.jar</packagingExcludes>
        <escapeString>\</escapeString>
        </configuration>
       </plugin>
       <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.4</version>
        <configuration>
                 <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                 </descriptorRefs>
             <archive>
            <manifest>
        <mainClass>com.dca.engine.StartDCA</mainClass>
            </manifest>
             </archive>
        </configuration>
        <executions>
             <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                      <goal>single</goal>
                    </goals>
             </execution>
        </executions>
    </plugin>
 </plugins>
<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
        <include>**/*.java</include>
        <include>**/*.xml</include>
        </includes>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
    </resource>
</resources>
</build>

嵌入式Jetty。
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
    <version>8.1.10.v20130312</version>
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-webapp</artifactId>
    <version>8.1.10.v20130312</version>
    <!-- <scope>provided</scope> -->
</dependency>
<dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-jsp</artifactId>
    <version>8.1.10.v20130312</version>
    <!-- <scope>provided</scope>  -->
</dependency> 

main method

 Server server = new Server(8080);
        System.setProperty("is_DCA", "YES");
        WebAppContext webAppContext = new WebAppContext();
        webAppContext.setResourceBase("/home/myfolder/workspace/app/dca/src/main/webapp");
        webAppContext.setDescriptor("/home/myfolder/workspace/app/dca/src/main/webapp/WEB-INF/web.xml");
        webAppContext.setContextPath("/app");
        server.setHandler(webAppContext);
        server.start();
        server.join();

启动应用程序

我使用 java -jar /home/myfolder/workspace/app/dca/target/app-dca-1.0-jar-with-dependencies.jar 命令运行创建的 jar 文件。

然后,Jetty 出现异常。

INFO  10-12 15:03:01,609 - jetty-8.y.z-SNAPSHOT
INFO  10-12 15:03:01,776 - Initializing Spring root WebApplicationContext
INFO  10-12 15:03:01,776 - Root WebApplicationContext: initialization started
INFO  10-12 15:03:01,843 - Refreshing Root WebApplicationContext: startup date [Tue Dec 10 15:03:01 IST 2013]; root of context hierarchy
INFO  10-12 15:03:01,885 - Loading XML bean definitions from class path resource [applicationContext-dca.xml]
ERROR 10-12 15:03:05,725 - Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/util]
Offending resource: class path resource [applicationContext-dca.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:316)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1420)
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1413)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:184)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:140)
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:111)
    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)

有没有可能使用创建的war文件启动jetty。它在/WEB-INF/lib/文件夹中有jar文件,所有属性文件和xml文件都在/WEB-INF/lib/中,我尝试运行war文件

java -jar /home/myfolder/workspace/app/dca/target/app-dca-1.0.war

但它无法找到主类。

当创建可执行的war文件时,通过sumit的答案解决了问题

我遇到了这个问题的异常。当我将jetty版本替换为7.6.7.v20120910时,它可以工作。

我不知道为什么它不能与jetty 8.1.10.v20130312一起工作。


你的异常提示说applicationContext-dca.xml有问题?你确定/home/myfolder/workspace/app/dca/src/main/webapp/WEB-INF/web.xml是可执行war包正确的web.xml位置吗?我认为它应该是相对于war包的位置。 - Sumit
如何给出相对路径?假设我的jar包在/home/myfolder/app-dca-1.0.jar。 - jos
4个回答

9
如果您不强制使用Jetty,而是可以使用Tomcat,则以下内容非常适用:

如果你没有把 Jetty 和 Tomcat 搞混的话,这个建议很好用:

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.0</version>
    <executions>
        <execution>
            <id>tomcat-run</id>
            <goals>
                <goal>exec-war-only</goal>
            </goals>
            <phase>package</phase>
            <configuration>
                <path>/standalone</path>
                <enableNaming>false</enableNaming>
                <finalName>standalone.jar</finalName>
                <charset>utf-8</charset>
            </configuration>
        </execution>
    </executions>
</plugin>

这将创建一个名为“standalone.jar”的超级jar文件,您只需调用就可以运行它。
java -jar standalone.jar

这将在 http://localhost:8080/standalone 上启动应用程序。

选择另一个端口很容易。

java -jar standalone.jar -httpPort=7070

感谢Tomasz Nurkiewicz的博客文章,突出了这个独立的Web应用程序:http://www.nurkiewicz.com/2012/11/standalone-web-application-with.html

不行!它显示“INFO: Starting ProtocolHandler ["http-bio-8080"]”,但localhost:8080根本没有显示任何内容。此外,版本2.0还存在空指针异常。 - 3xCh1_23
对我来说很好用,但URL必须是http://localhost:8080/standalone,因为配置路径是/standalone。 - pdem

8

被接受的答案所做的内容不同,您可以使用maven-shade-plugin创建可执行的JAR文件,这具有以下优点:

  • 该插件包含用于合并META-INF / services、LICENSE和README文件内容的“转换器”。
  • 您最终得到的是JAR文件。WAR文件不是为可执行而设计的(尽管它可以工作)。
  • 通过将所有依赖项解压缩到同一个JAR文件中,您被迫删除重复的类并使内容更难以反向工程化。

我正在做这个,但不确定在主方法中该怎么做。关于war文件的引用失败了,说找不到war文件。而且war文件不在jar包里,真是够了。我该如何让Maven Shade包含war文件?这似乎有点奇怪,但如果它能工作那就行了。 - barclay
@kewpiedoll99,你不使用WAR文件,没有讨论的余地。首先,你需要想办法从未打包的目录结构中运行Jetty(这是你需要谷歌的另一个问题)。一旦你解决了这个问题,从可执行JAR文件中运行就会顺利进行。 - Gili

3
请查看http://uguptablog.blogspot.com/2012/09/embedded-jetty-executable-war-with.html,其中的相关代码如下:
    ProtectionDomain domain = Main.class.getProtectionDomain();
    URL location = domain.getCodeSource().getLocation();
    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setWar(location.toExternalForm());
    server.setHandler(webapp);

希望能够帮上忙。

请问您能否在博客中添加一些理论知识?另外,为什么可执行的JAR文件不会像创建包的文件夹结构一样在WEB-INF中获取类,而是创建一个文件夹结构来存储所有依赖的JAR文件呢? - jos
当我尝试您的代码时,出现了以下异常:org.apache.jasper.JasperException: /common/taglibs.jsp(5,62) PWC6188: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:92) - jos
我不知道为什么会出现这个错误,是因为 jar 冲突吗?我在创建的 war 文件的 /WEB-INF/lib/ 目录下有 jstl-1.2.jar。同时,另外一个文件夹 /javax/servlet/jsp/jstl/ 也被创建了,并且其中包含了 core、fmt、sql 和 tlv 文件夹。 - jos
抱歉,这不是我的博客。但是你可能需要在web-inf/tld文件夹中使用tld文件。 - Sumit

2
我知道的最简单的方法(但从未尝试过)是使用,就像Jenkins CI所做的那样(这是一个更好的例子:D)。 它不使用Jetty(即使我喜欢这个工具:D),而是使用Winstone。

Maven插件用法

<plugin>
    <groupId>net.sf.alchim</groupId>
    <artifactId>winstone-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>embed</goal>
            </goals>
            <phase>package</phase>
        </execution>
    </executions>
</plugin>

很容易,不是吗? :) 它将生成一个可执行的独立jar包:app-dca-1.0-standalone.jar 文档
- Winstone Servlet容器: http://winstone.sourceforge.net/ - Winstone Maven插件: http://alchim.sourceforge.net/winstone-maven-plugin/usage.html - 完整示例: http://www.jayway.com/2008/11/28/executable-war-with-winstone-maven-plugin/

哦... Winstone Maven 插件似乎对最新版本的 Maven 来说太旧了。我尝试使用它时立即遇到了 NullPointerException。 - Eric
确实,这个答案在技术演进方面已经有些过时了。就目前而言,我会(也确实使用)spring-boot 来满足这种需求。 - Jean-Rémy Revy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接