Java 无需maven即可启动jetty的可执行war文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2458440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Executable war file that starts jetty without maven
提问by twilbrand
I'm trying to make an "executable" war file (java -jar myWarFile.war
) that will start up a Jetty webserver that hosts the webapp contained in the WAR file I executed.
我正在尝试制作一个“可执行的”war 文件 ( java -jar myWarFile.war
),它将启动一个 Jetty 网络服务器,该服务器托管我执行的 WAR 文件中包含的 web 应用程序。
I found a pagethat described how to make what I'm looking for:
我找到了一个页面,描述了如何制作我正在寻找的东西:
However, following that advice along with how I think I'm supposed to make an executable jar (war) isn't working.
但是,遵循该建议以及我认为应该如何制作可执行 jar (war) 是行不通的。
I have an Ant task creating a WAR file with a manifest that looks like:
我有一个 Ant 任务创建一个 WAR 文件,其清单如下所示:
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 1.5.0_18-b02 (Sun Microsystems Inc.) Main-Class: Start
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.7.1 Created-By: 1.5.0_18-b02 (Sun Microsystems Inc.) Main-Class: Start
The contents of the WAR file look like:
WAR 文件的内容如下所示:
> Start.class
> jsp
> build.jsp
> META-INF
> MANIFEST.MF
> WEB-INF
> lib
> jetty-6.1.22.jar
> jetty-util.6.1.22.jar
When I try to execute the WAR file, the error is:
当我尝试执行 WAR 文件时,错误是:
Exception in thread "main" java.lang.NoClassDefFoundError: org/mortbay/jetty/Handler
Caused by: java.lang.ClassNotFoundException: org.mortbay.jetty.Handler
at java.net.URLClassLoader.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: Start. Program will exit.
There appears to be two errors here: one where it seems the JAR files can't be found, and one where the Start
class can't be found.
这里似乎有两个错误:一个似乎找不到 JAR 文件,一个Start
是找不到类。
To fix the first one, I put the Jetty JAR files in the base of the WAR file and tried again -- same error. I also tried adding the WEB-INF/lib/<specific-JAR-files>
to the Class-Path
attribute of the manifest. That did not work either.
为了修复第一个,我将 Jetty JAR 文件放在 WAR 文件的基础中并再次尝试——同样的错误。我还尝试将 加入WEB-INF/lib/<specific-JAR-files>
到Class-Path
清单的属性中。那也没有用。
Does anyone have any insight as to what I'm doing right/wrong and how I can get this executable WAR file up and running?
有没有人知道我在做什么对/错,以及如何启动和运行这个可执行的 WAR 文件?
采纳答案by Rob Hruska
The linkyou have in your question provides most of what you need. However, there are a few things that need to be done in addition to that.
您在问题中的链接提供了您需要的大部分内容。但是,除此之外,还有一些事情需要做。
Any class files that Jetty needs to start up will need to be located at the root of the war file when it's packaged. We can leverage Ant to do that for us before we <war>
the file. The war's manifest file will also need a Main-Class
attribute to execute the server.
Jetty 需要启动的任何类文件在打包时都需要位于 war 文件的根目录下。我们可以<war>
在文件之前利用 Ant 为我们做这件事。战争的清单文件还需要一个Main-Class
属性来执行服务器。
Here's a step-by-step:
这是一个分步说明:
Create your Jetty server class:
创建您的 Jetty 服务器类:
This is adapted from the link you provided.
这是根据您提供的链接改编的。
package com.mycompany.myapp;
import java.io.File;
import java.net.URL;
import java.security.ProtectionDomain;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.webapp.WebAppContext;
public final class EmbeddedJettyServer
{
public static void main(String[] args) throws Exception
{
int port = Integer.parseInt(System.getProperty("port", "8080"));
Server server = new Server(port);
ProtectionDomain domain = EmbeddedJettyServer.class.getProtectionDomain();
URL location = domain.getCodeSource().getLocation();
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setDescriptor(location.toExternalForm() + "/WEB-INF/web.xml");
webapp.setServer(server);
webapp.setWar(location.toExternalForm());
// (Optional) Set the directory the war will extract to.
// If not set, java.io.tmpdir will be used, which can cause problems
// if the temp directory gets cleaned periodically.
// Your build scripts should remove this directory between deployments
webapp.setTempDirectory(new File("/path/to/webapp-directory"));
server.setHandler(webapp);
server.start();
server.join();
}
}
To see what all you can configure here, have a look at the Jetty API documentation.
要查看您可以在此处配置的所有内容,请查看Jetty API 文档。
Build the war with Ant:
与蚂蚁建立战争:
This uses a staging directory to unpack the necessary class files into the root of the war so they're accessible when the war is executed.
这使用临时目录将必要的类文件解压缩到战争的根目录中,以便在执行战争时可以访问它们。
<target name="war" description="--> Creates self-executing war">
<property name="staging.dir" location="${basedir}/staging"/>
<property name="webapp.dir" location="${basedir}/src/webapp"/>
<mkdir dir="${staging.dir}"/>
<!-- assumes you have all of your war content (excluding classes and libraries) already structured in a directory called src/webapp -->
<!-- e.g. -->
<!-- src/webapp/index.html -->
<!-- src/webapp/WEB-INF/web.xml -->
<!-- src/webapp/WEB-INF/classes/my.properties -->
<!-- etc ... -->
<copy todir="${staging.dir}">
<fileset dir="${webapp.dir}" includes="**/*"/>
</copy>
<unjar dest="${staging.dir}">
<!-- you'll have to locate these jars or appropriate versions; note that these include JSP support -->
<!-- you might find some of them in the downloaded Jetty .tgz -->
<fileset dir="path/to/jetty/jars">
<include name="ant-1.6.5.jar"/>
<include name="core-3.1.1.jar"/>
<include name="jetty-6.1.24.jar"/>
<include name="jsp-2.1-glassfish-2.1.v20091210.jar"/><!-- your JSP implementation may vary -->
<include name="jsp-api-2.1-glassfish-2.1.v20091210.jar"/><!-- your JSP implementation may vary -->
<include name="servlet-api-2.5-20081211.jar"/><!-- your Servlet API implementation may vary -->
</fileset>
<patternset><!-- to exclude some of the stuff we don't really need -->
<exclude name="META-INF/**/*"/>
<exclude name="images/**/*"/>
<exclude name=".options"/>
<exclude name="about.html"/>
<exclude name="jdtCompilerAdapter.jar"/>
<exclude name="plugin*"/>
</patternset>
</unjar>
<!-- copy in the class file built from the above EmbeddedJettyServer.java -->
<copy todir="${staging.dir}">
<fileset dir="path/to/classes/dir" includes="com/mycompany/myapp/EmbeddedJettyServer.class"/>
</copy>
<war destfile="myapp.war" webxml="${webapp.dir}/WEB-INF/web.xml">
<fileset dir="${staging.dir}" includes="**/*"/>
<classes dir="path/to/classes/dir"/><!-- your application classes -->
<lib dir="path/to/lib/dir"/><!-- application dependency jars -->
<manifest>
<!-- add the Main-Class attribute that will execute our server class -->
<attribute name="Main-Class" value="com.mycompany.myapp.EmbeddedJettyServer"/>
</manifest>
</war>
<delete dir="${staging.dir}"/>
</target>
Execute the war:
执行战争:
If everything's set up properly above, you should be able to:
如果上面的一切设置正确,您应该能够:
java -jar myapp.war
// or if you want to configure the port (since we are using the System property in the code)
java -Dport=8443 -jar myapp.war
回答by Sean Owen
- Putting .jars inside a .war file root does nothing
- Putting .jars inside
WEB-INF/lib
doesn't help the JVM find the Jetty files to even begin launching your .war. It's "too late" to put them there. - Putting .jars in the manifest Class-Path only works for external .jar files, not those contained in the .jar
- 将 .jars 放在 .war 文件根目录中没有任何作用
- 将 .jars 放入其中
WEB-INF/lib
并不能帮助 JVM 找到 Jetty 文件,甚至无法启动您的 .war。把它们放在那里“太晚了”。 - 将 .jars 放在清单 Class-Path 中仅适用于外部 .jar 文件,不适用于 .jar 中包含的文件
So what to do?
那么该怎么办?
- Use a build script to simply merge all the .jar files you need into the .war file. This takes a little extra work. It's also a bit ugly in that the compiled code is part of the servable files in the .war
- Add dependent .jars to the JVM's classpath with "java -cp jetty.jar:... ..." Works though this kind of defeats the purpose of one stand-alone .war
- 使用构建脚本将您需要的所有 .jar 文件简单地合并到 .war 文件中。这需要一些额外的工作。它也有点难看,因为编译后的代码是 .war 中可服务文件的一部分
- 使用“java -cp jetty.jar:... ...”将依赖的 .jars 添加到 JVM 的类路径中,尽管这种方式违背了一个独立 .war 的目的
回答by Kannan Ekanath
I have done a similar thing before but are you launchign the app as "java -jar xxx.war" ?. You have only 2 jars and it is not going to be enough I think. Also try using Jetty 7.0.0M1 (which is the latest version). When I added jetty-server and jetty-webapp as two dependencies (they are from org.eclipse.jetty) I get the following jar's in the lib directory. FYI the org.mortbay.jetty.Handler was in the jetty-server*.jar.
我以前做过类似的事情,但是您将应用程序启动为“java -jar xxx.war”吗?。你只有 2 个罐子,我想这还不够。也尝试使用 Jetty 7.0.0M1(这是最新版本)。当我添加 jetty-server 和 jetty-webapp 作为两个依赖项(它们来自 org.eclipse.jetty)时,我在 lib 目录中得到以下 jar。仅供参考,org.mortbay.jetty.Handler 位于 jetty-server*.jar 中。
- jetty-continuation-7.0.0.M1.jar
- jetty-http-7.0.0.M1.jar
- jetty-io-7.0.0.M1.jar
- jetty-security-7.0.0.M1.jar
- jetty-server-7.0.0.M1.jar
- jetty-servlet-7.0.0.M1.jar
- jetty-util-7.0.0.M1.jar
- jetty-webapp-7.0.0.M1.jar
- jetty-xml-7.0.0.M1.jar
- jetty-continuation-7.0.0.M1.jar
- 码头-http-7.0.0.M1.jar
- jetty-io-7.0.0.M1.jar
- jetty-security-7.0.0.M1.jar
- jetty-server-7.0.0.M1.jar
- jetty-servlet-7.0.0.M1.jar
- jetty-util-7.0.0.M1.jar
- jetty-webapp-7.0.0.M1.jar
- jetty-xml-7.0.0.M1.jar
回答by Thorbj?rn Ravn Andersen
Hudson solves this exact problem using the Winstone servlet container, which supports this use case directly. http://winstone.sourceforge.net/#embedding
Hudson 使用直接支持此用例的 Winstone servlet 容器解决了这个确切的问题。 http://winstone.sourceforge.net/#embedding
Perhaps this would work for you?
也许这对你有用?
回答by Mark O'Connor
This is my example ANT extract. The idea is to unpackage the Jetty dependencies and then include them locally just like a normal JAR file:
这是我的示例 ANT 提取物。这个想法是解包 Jetty 依赖项,然后像普通 JAR 文件一样将它们包含在本地:
<!-- Hack: Java doesn't support jars within jars/wars -->
<unjar src="${lib.dir}/container/jetty.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/jetty-util.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/servlet-api.jar" dest="${build.dir}/unjar"/>
<unjar src="${lib.dir}/container/jsp-api.jar" dest="${build.dir}/unjar"/>
<!-- Build war file as normal, just including the compiled and unjar'ed files -->
<war destfile="${war.file}" webxml="${config.dir}/web.xml">
<fileset dir="${build.dir}/classes"/>
<fileset dir="${build.dir}/unjar"/>
<fileset dir="${resources.dir}" excludes="*.swp"/>
<lib dir="${lib.dir}/runtime"/>
<manifest>
<attribute name="Main-Class" value="Start"/>
</manifest>
</war>
Note:
笔记:
The WEB-INF/libdirecory is for the web applications dependencies. In this case we're packaging the WAR file so that it works like the normal Jetty JAR file on startup
在WEB-INF / lib目录猪病是Web应用程序的依赖关系。在这种情况下,我们将打包 WAR 文件,以便它在启动时像普通的 Jetty JAR 文件一样工作
回答by Rodney Beede
Even though this is kind of old another alternative with Jetty 8 is to simply include the Jetty jars as dependencies in your pom and add the following in your pom (versus an ant script that unpackages the war and repackages it):
尽管这有点旧,但 Jetty 8 的另一种替代方法是简单地将 Jetty jar 作为依赖项包含在你的 pom 中,并在你的 pom 中添加以下内容(而不是解包战争并重新打包它的 ant 脚本):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>JettyStandaloneMain</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- The main class needs to be in the root of the war in order to be
runnable -->
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>move-main-class</id>
<phase>compile</phase>
<configuration>
<tasks>
<move todir="${project.build.directory}/${project.build.finalName}">
<fileset dir="${project.build.directory}/classes/">
<include name="JettyStandaloneMain.class" />
</fileset>
</move>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
回答by schmmd
I take it that by "without maven" you want a jar that you can run by itself and not with "mvn jetty:run"--not that you don't want to use maven at all.
我认为通过“没有 maven”,您需要一个可以自行运行的 jar,而不是“mvn jetty:run”——并不是说您根本不想使用 maven。
It took me way to long to figure this out because I found many options--none of them dirt simple. Eventually I found this maven plugin from simplericity. It works wonderfully.
我花了很长时间才弄明白这一点,因为我找到了很多选择——没有一个是简单的。最终我从 simplericity找到了这个 maven 插件。它工作得很好。
回答by Rafael Sanches
We have figured this out by using jetty-console-maven-plugin.
我们已经通过使用 jetty-console-maven-plugin 解决了这个问题。
Whenever you run mvn package it creates another war that can be used with java -jar whateverpackage-runnable.war
每当您运行 mvn package 时,它都会创建另一个可与 java -jarwhateverpackage-runnable.war 一起使用的战争
<plugin>
<groupId>org.simplericity.jettyconsole</groupId>
<artifactId>jetty-console-maven-plugin</artifactId>
<version>1.45</version>
<executions>
<execution>
<goals>
<goal>createconsole</goal>
</goals>
</execution>
</executions>
<configuration>
<additionalDependencies>
<additionalDependency>
<artifactId>jetty-console-requestlog-plugin</artifactId>
</additionalDependency>
<additionalDependency>
<artifactId>jetty-console-gzip-plugin</artifactId>
</additionalDependency>
<additionalDependency>
<artifactId>jetty-console-ajp-plugin</artifactId>
</additionalDependency>
<additionalDependency>
<artifactId>jetty-console-startstop-plugin</artifactId>
</additionalDependency>
</additionalDependencies>
</configuration>
</plugin>
It also generates the init.d scripts and everything for you!
它还为您生成 init.d 脚本和所有内容!
回答by AhHatem
This is an adaptation for Maven of @RobHruska's answer. It just copies the files of the main class and merges the Jetty JAR files into the WAR file, nothing new, just to simplify your life if you are new -like me- to Maven:
这是对@RobHruska 答案的 Maven 的改编。它只是复制主类的文件并将 Jetty JAR 文件合并到 WAR 文件中,没什么新鲜的,只是为了简化你的生活,如果你是 Maven 新手——就像我一样:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>move-main-class</id>
<phase>compile</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/${project.build.finalName}">
<fileset dir="${project.build.directory}/${project.build.finalName}/WEB-INF/classes/">
<include name="main/*.class" />
</fileset>
</copy>
<unjar dest="${project.build.directory}/${project.build.finalName}">
<!-- you'll have to locate these jars or appropriate versions; note that these include JSP support -->
<!-- you might find some of them in the downloaded Jetty .tgz -->
<fileset dir="${project.build.directory}/${project.build.finalName}/WEB-INF/lib/">
<include name="ant-1.6.5.jar"/>
<!--<include name="core-3.1.1.jar"/>-->
<include name="jetty*"/>
<include name="servlet-api*"/>
</fileset>
<patternset><!-- to exclude some of the stuff we don't really need -->
<exclude name="META-INF/**/*"/>
<exclude name="images/**/*"/>
<exclude name=".options"/>
<exclude name="about.html"/>
<exclude name="jdtCompilerAdapter.jar"/>
<exclude name="plugin*"/>
</patternset>
</unjar>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<archiveClasses>true</archiveClasses>
<archive>
<manifest>
<mainClass>main.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>