带有 Maven 示例的嵌入式 Jetty 无法重新启动:地址已在使用中

Embedded Jetty with Maven example fails to restart: Address already in use

当尝试在 NetBeans 中重复 运行 和 Embedded Jetty with Maven example 时,不幸的是我得到了错误:

cd /Users/afarber/src/JettyMavenHelloWorld; JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home "/Applications/NetBeans/NetBeans 8.1.app/Contents/Resources/NetBeans/java/maven/bin/mvn" "-Dexec.args=-classpath %classpath org.example.HelloWorld" -Dexec.executable=/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java org.codehaus.mojo:exec-maven-plugin:1.2.1:exec
Running NetBeans Compile On Save execution. Phase execution is skipped and output directories of dependency projects (with Compile on Save turned on) will be used instead of their jar artifacts.
Scanning for projects...

------------------------------------------------------------------------
Building Jetty HelloWorld 0.1-SNAPSHOT
------------------------------------------------------------------------

--- exec-maven-plugin:1.2.1:exec (default-cli) @ hello-world ---
2016-05-24 19:01:26.748:INFO:oejs.Server:main: jetty-9.0.2.v20130417
2016-05-24 19:01:26.817:WARN:oejuc.AbstractLifeCycle:main: FAILED ServerConnector@7591083d{HTTP/1.1}{0.0.0.0:8080}: java.net.BindException: Address already in use
java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:437)
    at sun.nio.ch.Net.bind(Net.java:429)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:227)
    at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.eclipse.jetty.server.Server.doStart(Server.java:309)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.example.HelloWorld.main(HelloWorld.java:29)
2016-05-24 19:01:26.818:WARN:oejuc.AbstractLifeCycle:main: FAILED org.eclipse.jetty.server.Server@77a567e1: java.net.BindException: Address already in use
java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:437)
    at sun.nio.ch.Net.bind(Net.java:429)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:227)
    at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.eclipse.jetty.server.Server.doStart(Server.java:309)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.example.HelloWorld.main(HelloWorld.java:29)
Exception in thread "main" java.net.BindException: Address already in use
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:437)
    at sun.nio.ch.Net.bind(Net.java:429)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:227)
    at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.eclipse.jetty.server.Server.doStart(Server.java:309)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:69)
    at org.example.HelloWorld.main(HelloWorld.java:29)

如果根本原因是绑定侦听套接字时的 SO_REUSEADDR 限制 - 那么可能 ServerSocket.setReuseAddress(true) 会有所帮助。

但是在 HelloWorld.java 中如何以及在何处调用它?

package org.example;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import java.io.IOException;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class HelloWorld extends AbstractHandler
{
    public void handle(String target,
                       Request baseRequest,
                       HttpServletRequest request,
                       HttpServletResponse response)
        throws IOException, ServletException
    {
        response.setContentType("text/html;charset=utf-8");
        response.setStatus(HttpServletResponse.SC_OK);
        baseRequest.setHandled(true);
        response.getWriter().println("<h1>Hello World</h1>");
    }

    public static void main(String[] args) throws Exception
    {
        Server server = new Server(8080);
        server.setHandler(new HelloWorld());
        server.start();
        server.join();
    }
}

我正在使用以下 pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example</groupId>
  <artifactId>hello-world</artifactId>
  <version>0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>Jetty HelloWorld</name>

  <properties>
      <jettyVersion>9.3.9.v20160517</jettyVersion>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-server</artifactId>
      <version>${jettyVersion}</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.1</version>
        <executions>
          <execution><goals><goal>java</goal></goals></execution>
        </executions>
        <configuration>
          <mainClass>org.example.HelloWorld</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

更新:

Lars Gendner 是正确的,我的 Macbook 上仍然有 HelloWorld 进程 运行:

# ps -ef | grep HelloWorld
  501   944     1   0  6:58pm ??         0:04.20 /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java -classpath /Users/afarber/src/JettyMavenHelloWorld/target/classes:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-server/9.0.2.v20130417/jetty-server-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/orbit/javax.servlet/3.0.0.v201112011016/javax.servlet-3.0.0.v201112011016.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-http/9.0.2.v20130417/jetty-http-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.0.2.v20130417/jetty-util-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.0.2.v20130417/jetty-io-9.0.2.v20130417.jar org.example.HelloWorld
  501   948     1   0  6:58pm ??         0:03.89 /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/bin/java -classpath /Users/afarber/src/JettyMavenHelloWorld/target/classes:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-server/9.0.2.v20130417/jetty-server-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/orbit/javax.servlet/3.0.0.v201112011016/javax.servlet-3.0.0.v201112011016.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-http/9.0.2.v20130417/jetty-http-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-util/9.0.2.v20130417/jetty-util-9.0.2.v20130417.jar:/Users/afarber/.m2/repository/org/eclipse/jetty/jetty-io/9.0.2.v20130417/jetty-io-9.0.2.v20130417.jar org.example.HelloWorld

端口 8080 正在使用中:

# netstat -an | grep -w 8080
tcp46      0      0  *.8080                 *.*                    LISTEN     

但我当然不想一次又一次地更改端口号(并产生更多进程)。

相反(作为 NetBeans 和 Jetty 新手)我想知道如何正确停止 NetBeans 中的嵌入式 Jetty? (除了 awk /HelloWorld/ '{print }'| xargs kill 解决方法)

更新 2:

jetty-maven-plugin添加到pom.xml和运行ningmvn jetty:run确实在端口8080启动了一个网络服务器,但它只显示红色文本:

Directory: /

这是完整的 Maven 输出:

# mvn jetty:run
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Jetty HelloWorld 0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] >>> jetty-maven-plugin:9.3.9.v20160517:run (default-cli) > test-compile @ hello-world >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ hello-world ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ hello-world ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/classes
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ hello-world ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ hello-world ---
[INFO] No sources to compile
[INFO] 
[INFO] <<< jetty-maven-plugin:9.3.9.v20160517:run (default-cli) < test-compile @ hello-world <<<
[INFO] 
[INFO] --- jetty-maven-plugin:9.3.9.v20160517:run (default-cli) @ hello-world ---
[INFO] Configuring Jetty for project: Jetty HelloWorld
[INFO] webAppSourceDirectory not set. Trying src/main/webapp
[INFO] webAppSourceDirectory /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/src/main/webapp does not exist. Trying /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/webapp-tmp
[INFO] Reload Mechanic: automatic
[INFO] Classes = /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/classes
[INFO] Logging initialized @3610ms
[INFO] Context path = /
[INFO] Tmp directory = /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/tmp
[INFO] Web defaults = org/eclipse/jetty/webapp/webdefault.xml
[INFO] Web overrides =  none
[INFO] web.xml file = null
[INFO] Webapp directory = /Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/webapp-tmp
[INFO] jetty-9.3.9.v20160517
[INFO] Started o.e.j.m.p.JettyWebAppContext@58a63629{/,file:///Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/webapp-tmp/,AVAILABLE}{file:///Users/afarber/src/jetty-newbie/JettyMavenHelloWorld/target/webapp-tmp/}
[INFO] Started ServerConnector@75a118e6{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
[INFO] Started @4608ms
[INFO] Started Jetty Server
[INFO] Using Non-Native Java sun.nio.fs.PollingWatchService
[WARNING] Quiet Time is too low for non-native WatchService [sun.nio.fs.PollingWatchService]: 1000 < 5000 ms (defaulting to 5000 ms)

我很确定你已经在端口 8080 上有一个进程 运行。如果你找到那个进程并结束它(也许你试图启动 Jetty 两次而不是结束已经 运行 Jetty 实例正确吗?),您的进程应该可以正常启动。

您也可以尝试使用其他端口代替 8080(例如 8090)。

您应该将 jetty-maven-plugin 添加到您的 pom 并尝试停止服务器。 jetty stop 目标查找插件配置。请参考这个 jetty 文档 Jetty Stop goal

The stop goal stops a running instance of jetty. To use it, you need to configure the plugin with a special port number and key. That same port number and key will also be used by the other goals that start jetty.

这里是jetty-stop的插件配置,

<plugin>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>@project.version@</version>
  <configuration>
    <stopPort>9966</stopPort>
    <stopKey>foo</stopKey>
    <stopWait>10</stopWait>
  </configuration>
</plugin>

并且在jetty启动之后,执行下面的命令,

mvn jetty:stopmvn jetty:stop

或者干脆试试

mvn jetty:stop

mvn jetty:run命令将启动服务器。其他goals/configurations请参考Configuring Jetty Maven plugin