简体   繁体   English

在没有maven的情况下启动jetty的可执行war文件

[英]Executable war file that starts jetty without maven

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 web服务器,它托管我执行的WAR文件中包含的webapp。

I found a page that 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(战争)是不行的。

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 

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$1.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. 为了修复第一个,我将Jetty JAR文件放在WAR文件的基础上并再次尝试 - 同样的错误。 I also tried adding the WEB-INF/lib/<specific-JAR-files> to the Class-Path attribute of the manifest. 我还尝试将WEB-INF/lib/<specific-JAR-files>到清单的Class-Path属性中。 That did not work either. 那也行不通。

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文件启动并运行?

The link you 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. Jetty需要启动的任何类文件都需要在打包时位于war文件的根目录下。 We can leverage Ant to do that for us before we <war> the file. 在我们<war>文件之前,我们可以利用Ant为我们做这件事。 The war's manifest file will also need a Main-Class attribute to execute the server. war的manifest文件还需要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: 用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

This is an adaptation for Maven of @RobHruska's answer. 这是对@ RobHruska的答案Maven的改编。 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: 它只是复制主类的文件并将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>

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包,它都会创建另一个可以与java -jar一起使用的war-jetspackage-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脚本和一切!

Hudson solves this exact problem using the Winstone servlet container, which supports this use case directly. Hudson使用Winstone servlet容器解决了这个确切的问题,该容器直接支持这个用例。 http://winstone.sourceforge.net/#embedding http://winstone.sourceforge.net/#embedding

Perhaps this would work for you? 也许这对你有用吗?

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罐作为依赖项包含在你的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>

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 . 最终我从simplericity中找到了这个maven插件 It works wonderfully. 它运作得很好。

This is my example ANT extract. 这是我的ANT提取示例。 The idea is to unpackage the Jetty dependencies and then include them locally just like a normal JAR file: 我们的想法是解压缩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/lib direcory is for the web applications dependencies. WEB-INF / lib目录用于Web应用程序依赖项。 In this case we're packaging the WAR file so that it works like the normal Jetty JAR file on startup 在这种情况下,我们打包WAR文件,使其在启动时像普通的Jetty JAR文件一样工作

  • Putting .jars inside a .war file root does nothing 将.jars放在.war文件根目录中什么都不做
  • Putting .jars inside WEB-INF/lib doesn't help the JVM find the Jetty files to even begin launching your .war. 将.jars放在WEB-INF/lib并不能帮助JVM找到Jetty文件甚至开始启动.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放在清单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. 使用构建脚本将所需的所有.jar文件简单地合并到.war文件中。 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 它也有点难看,因为编译后的代码是.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 使用“java -cp jetty.jar:......”将依赖的.jars添加到JVM的类路径中。虽然这样做会破坏一个独立的.war的目的

I have done a similar thing before but are you launchign the app as "java -jar xxx.war" ?. 我之前做过类似的事情,但你是否将应用程序称为“java -jar xxx.war”? You have only 2 jars and it is not going to be enough I think. 你只有2个罐子,我觉得这还不够。 Also try using Jetty 7.0.0M1 (which is the latest version). 另请尝试使用Jetty 7.0.0M1(这是最新版本)。 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. 当我添加jetty-server和jetty-webapp作为两个依赖项(它们来自org.eclipse.jetty)时,我在lib目录中获得了以下jar。 FYI the org.mortbay.jetty.Handler was in the jetty-server*.jar. 仅供参考org.mortbay.jetty.Handler在jetty-server * .jar中。

  • jetty-continuation-7.0.0.M1.jar 码头 - 连续 - 7.0.0.M1.jar
  • jetty-http-7.0.0.M1.jar 码头-HTTP-7.0.0.M1.jar
  • jetty-io-7.0.0.M1.jar 码头-IO-7.0.0.M1.jar
  • jetty-security-7.0.0.M1.jar 码头安全,7.0.0.M1.jar
  • jetty-server-7.0.0.M1.jar 码头 - 服务器7.0.0.M1.jar
  • jetty-servlet-7.0.0.M1.jar 码头-servlet的7.0.0.M1.jar
  • jetty-util-7.0.0.M1.jar 码头-UTIL-7.0.0.M1.jar
  • jetty-webapp-7.0.0.M1.jar 码头-web应用,7.0.0.M1.jar
  • jetty-xml-7.0.0.M1.jar 码头的XML-7.0.0.M1.jar

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM