我正在Clojure中编写一个嵌入式Jetty应用程序,并将以下内容作为主命名空间:
(ns rudkus.core
(:require [clojure.tools.cli :as cli]
[ring.adapter.jetty :as jetty])
(:gen-class))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello, World!"})
(def ^{:private true} server (atom nil))
(defn start [port]
(swap! server #(if (not (nil? %))
(throw (IllegalStateException. "Server already started."))
(jetty/run-jetty handler
{:port port
:join? false}))))
(defn stop []
(swap! server #(if (nil? %)
(throw (IllegalStateException. "Server already stopped."))
(do (.stop %)
nil))))
(defn -main [& args]
(let [[options extra-args banner] (cli/cli args
["-p" "--port" "Port" :default 80 :parse-fn #(Integer. %)])]
(if (not-empty extra-args)
(println banner)
(start (:port options)))))
这可以正常工作 - 我希望能够通过REPL启动和停止,以及从运行JAR的控制台启动和启动(尽管有一个更好的模式来启动/停止Clojure-Ring - 快节目,我很想知道)。问题是如果我运行
lein run
或
lein trampoline run
并且jetty / run-jetty抛出异常(包装了一个Server.start()调用) - 例如,在我的MacBook Pro上,如果我尝试在端口80上启动Jetty服务器,它会barfs - Clojure计划不会退出。但是,例外是在线程“main”中。那么为什么程序不会退出呢?我唯一能想到的是Jetty有浮动的线程。但是start()失败了!那么这些线程(池)正在做什么?
这是Java的东西,Clojure的东西,Leiningen的东西,Jetty的东西,还是戒指的东西?
编辑:
这是stacktrace:
$ java -jar rudkus-0.1.0-SNAPSHOT-standalone.jar
2012-09-09 15:54:59.664:INFO:oejs.Server:jetty-7.x.y-SNAPSHOT
2012-09-09 15:54:59.803:WARN:oejuc.AbstractLifeCycle:FAILED SelectChannelConnector@0.0.0.0:80: java.net.SocketException: Permission denied
java.net.SocketException: Permission denied
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:124)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at org.eclipse.jetty.server.nio.SelectChannelConnector.open(SelectChannelConnector.java:173)
at org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:311)
at org.eclipse.jetty.server.nio.SelectChannelConnector.doStart(SelectChannelConnector.java:251)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at org.eclipse.jetty.server.Server.doStart(Server.java:272)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at ring.adapter.jetty$run_jetty.invoke(jetty.clj:86)
at rudkus.core$start$fn__16.invoke(core.clj:16)
at clojure.lang.Atom.swap(Atom.java:37)
at clojure.core$swap_BANG_.invoke(core.clj:2108)
at rudkus.core$start.invoke(core.clj:14)
at rudkus.core$_main.doInvoke(core.clj:31)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at rudkus.core.main(Unknown Source)
2012-09-09 15:54:59.806:WARN:oejuc.AbstractLifeCycle:FAILED org.eclipse.jetty.server.Server@6e5dfaf1: java.net.SocketException: Permission denied
java.net.SocketException: Permission denied
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:124)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at org.eclipse.jetty.server.nio.SelectChannelConnector.open(SelectChannelConnector.java:173)
at org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:311)
at org.eclipse.jetty.server.nio.SelectChannelConnector.doStart(SelectChannelConnector.java:251)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at org.eclipse.jetty.server.Server.doStart(Server.java:272)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at ring.adapter.jetty$run_jetty.invoke(jetty.clj:86)
at rudkus.core$start$fn__16.invoke(core.clj:16)
at clojure.lang.Atom.swap(Atom.java:37)
at clojure.core$swap_BANG_.invoke(core.clj:2108)
at rudkus.core$start.invoke(core.clj:14)
at rudkus.core$_main.doInvoke(core.clj:31)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at rudkus.core.main(Unknown Source)
Exception in thread "main" java.net.SocketException: Permission denied
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:124)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at org.eclipse.jetty.server.nio.SelectChannelConnector.open(SelectChannelConnector.java:173)
at org.eclipse.jetty.server.AbstractConnector.doStart(AbstractConnector.java:311)
at org.eclipse.jetty.server.nio.SelectChannelConnector.doStart(SelectChannelConnector.java:251)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at org.eclipse.jetty.server.Server.doStart(Server.java:272)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:59)
at ring.adapter.jetty$run_jetty.invoke(jetty.clj:86)
at rudkus.core$start$fn__16.invoke(core.clj:16)
at clojure.lang.Atom.swap(Atom.java:37)
at clojure.core$swap_BANG_.invoke(core.clj:2108)
at rudkus.core$start.invoke(core.clj:14)
at rudkus.core$_main.doInvoke(core.clj:31)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at rudkus.core.main(Unknown Source)
答案 0 :(得分:2)
如果您查看此代码(在Google搜索结果的第一页上找到答案),则有一个解决方案:source code containing method contextStartupFailed()该解决方案对我不起作用,因为它要求使用名为_unavailable的字段反射,我的Jetty版本(8.1.8.v20121106)没有这样的字段。
但是,Jetty现在可以提供更好的支持。对我来说,以下工作:
protected static void contextStartupFailed(WebAppContext pContext) throws Exception {
Throwable failedException = pContext.getUnavailableException();
if (failedException != null) {
throw new RuntimeException("Error starting WebContext of Jetty.", failedException);
}
}
我在启动Jetty之后调用该方法。当然,这仅在您拥有WebAppContext时才有效。