簡體   English   中英

在沒有maven的情況下啟動jetty的可執行war文件

[英]Executable war file that starts jetty without maven

我正在嘗試創建一個“可執行”war文件( java -jar myWarFile.war ),它將啟動一個Jetty web服務器,它托管我執行的WAR文件中包含的webapp。

我找到了一個頁面 ,描述了如何制作我正在尋找的東西:

然而,遵循這個建議以及我認為我應該制作一個可執行jar(戰爭)是不行的。

我有一個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 

WAR文件的內容如下所示:

> Start.class
> jsp
>   build.jsp 
> META-INF  
>   MANIFEST.MF
> WEB-INF
>   lib
>     jetty-6.1.22.jar
>     jetty-util.6.1.22.jar

當我嘗試執行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.

這里似乎有兩個錯誤:一個似乎無法找到JAR文件,另一個無法找到Start類。

為了修復第一個,我將Jetty JAR文件放在WAR文件的基礎上並再次嘗試 - 同樣的錯誤。 我還嘗試將WEB-INF/lib/<specific-JAR-files>到清單的Class-Path屬性中。 那也行不通。

有沒有人知道我正在做什么是對/錯我怎么能讓這個可執行的WAR文件啟動並運行?

您在問題中的鏈接提供了您需要的大部分內容。 但是,除此之外還有一些事情需要做。

Jetty需要啟動的任何類文件都需要在打包時位於war文件的根目錄下。 在我們<war>文件之前,我們可以利用Ant為我們做這件事。 war的manifest文件還需要Main-Class屬性來執行服務器。

這是一步一步:

創建您的Jetty服務器類:

這是根據您提供的鏈接改編的。

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();
    }
}

要查看您在此處可以配置的內容,請查看Jetty API文檔

用Ant建立戰爭:

這使用一個臨時目錄將必要的類文件解壓縮到戰爭的根目錄中,以便在執行戰爭時可以訪問它們。

<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>

執行戰爭:

如果一切都在上面正確設置,你應該能夠:

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

這是對@ 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>

我們通過使用jetty-console-maven-plugin來解決這個問題。

無論什么時候運行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>

它還為您生成init.d腳本和一切!

Hudson使用Winstone servlet容器解決了這個確切的問題,該容器直接支持這個用例。 http://winstone.sourceforge.net/#embedding

也許這對你有用嗎?

雖然這是舊的另一種替代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>

我認為通過“沒有maven”你想要一個可以自己運行的jar而不是“mvn jetty:run” - 而不是你根本不想使用maven。

我花了很長時間來解決這個問題,因為我找到了很多選擇 - 其中沒有一個很簡單。 最終我從simplericity中找到了這個maven插件 它運作得很好。

這是我的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>

注意:

WEB-INF / lib目錄用於Web應用程序依賴項。 在這種情況下,我們打包WAR文件,使其在啟動時像普通的Jetty JAR文件一樣工作

  • 將.jars放在.war文件根目錄中什么都不做
  • 將.jars放在WEB-INF/lib並不能幫助JVM找到Jetty文件甚至開始啟動.war。 將它們放在那里“為時已晚”。
  • 將.jars放在清單Class-Path中僅適用於外部.jar文件,而不適用於.jar中包含的文件

那么該怎么辦?

  • 使用構建腳本將所需的所有.jar文件簡單地合並到.war文件中。 這需要一些額外的工作。 它也有點難看,因為編譯后的代碼是.war中可維護文件的一部分
  • 使用“java -cp jetty.jar:......”將依賴的.jars添加到JVM的類路徑中。雖然這樣做會破壞一個獨立的.war的目的

我之前做過類似的事情,但你是否將應用程序稱為“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中。

  • 碼頭 - 連續 - 7.0.0.M1.jar
  • 碼頭-HTTP-7.0.0.M1.jar
  • 碼頭-IO-7.0.0.M1.jar
  • 碼頭安全,7.0.0.M1.jar
  • 碼頭 - 服務器7.0.0.M1.jar
  • 碼頭-servlet的7.0.0.M1.jar
  • 碼頭-UTIL-7.0.0.M1.jar
  • 碼頭-web應用,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