[英]How to gracefully close an Endpoint when an exception occurs?
I've written a small JAX-WS webservice that I'm running outside a container with Endpoint.publish()
: 我编写了一个小型JAX-WS Web服务,我使用Endpoint.publish()
在容器外运行:
Endpoint endpoint = Endpoint.create(new MyServiceImpl());
endpoint.publish("http://localhost:4425/myService");
If any of my web service methods throws an exception, the endpoint is not gracefully closed and the address remains in use until Windows eventually releases it. 如果我的任何Web服务方法抛出异常,则端点不会正常关闭,并且该地址将保持使用状态,直到Windows最终释放它为止。 This causes the classic error: 这会导致经典错误:
com.sun.xml.internal.ws.server.ServerRtException: Server Runtime Error: java.net.BindException: Address already in use: bind com.sun.xml.internal.ws.server.ServerRtException:服务器运行时错误:java.net.BindException:已在使用的地址:bind
I could wrap all of my web service methods with try/catch, but this seems a little repetitive. 我可以用try / catch包装所有的web服务方法,但这似乎有点重复。 I also tried installing a clean-up class via Thread.setDefaultUncaughtExceptionHandler()
, but this wasn't triggered when my web service method threw an exception. 我还尝试通过Thread.setDefaultUncaughtExceptionHandler()
安装一个清理类,但是当我的Web服务方法引发异常时,没有触发此类。
Is there a more elegant way of solving this than resorting to countless try/catch blocks? 是否有一种更优雅的解决方法,而不是诉诸无数的try / catch块?
Based on Waldheinz's answer, I've attempted to use Jetty classes in favour of JDK defaults. 根据Waldheinz的回答,我试图使用Jetty类来支持JDK默认值。 The code compiles, but when executed it terminates immediately after publish
. 代码编译,但在执行时,它会在publish
后立即终止。 When using JDK classes, the main thread would remain alive until I manually terminated the process. 使用JDK类时,主线程将保持活动状态,直到我手动终止该进程。 Any ideas what's going amiss? 有什么想法会有什么不妥? I wonder if an exception is happening somewhere but being swallowed so I can't see it. 我想知道是否有异常发生在某个地方,但被吞没,所以我看不到它。
Endpoint endpoint = Endpoint.create(new MyServiceImpl());
Server s = new Server(new InetSocketAddress(HOST, PORT));
ServerConnector connector = new ServerConnector(s);
connector.setReuseAddress(true);
s.setConnectors(new Connector[] { connector });
s.setHandler(new ContextHandlerCollection());
JettyHttpServer server = new JettyHttpServer(s, false);
JettyHttpContext context = (JettyHttpContext) server.createContext(PATH);
endpoint.publish(context);
Custom thread pool for an endpoint may help: 端点的自定义线程池可能有所帮助:
ThreadFactory factory = new ThreadFactory() {
@Override
public Thread newThread(Runnable target) {
final Thread thread = new Thread(target);
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
// put error handling code here
}
});
return thread;
}
};
ExecutorService executor = Executors.newCachedThreadPool(factory);
Endpoint endpoint = Endpoint.create(new MyServiceImpl());
endpoint.setExecutor(executor);
endpoint.publish("http://localhost:4425/myService");
如果绑定失败,但旧实例不再运行,则设置SO_REUSEADDR可能会有所帮助。
Using the hint from Waldheinz, I adjusted my web service to use Jetty as follows: 使用Waldheinz的提示,我调整了我的Web服务以使用Jetty,如下所示:
Server s = new Server(PORT);
ServerConnector connector = new ServerConnector(s);
connector.setReuseAddress(true); // avoid bind errors
s.setHandler(new ContextHandlerCollection());
s.setConnectors(new Connector[] { connector });
System.setProperty("com.sun.net.httpserver.HttpServerProvider",
"org.eclipse.jetty.http.spi.JettyHttpServerProvider");
Endpoint.publish(HOST + ":" + PORT + PATH, new MyServiceImpl());
This seems to be handling the problems well. 这似乎很好地处理了问题。 Bounty points go to Waldheinz for starting me down the right route. 恩惠积分去Waldheinz开始我正确的路线。 Thanks to Jk1 for an alternative suggestion. 感谢Jk1的替代建议。
I realize an answer's already been accepted, but it's unfortunate that it relies on a Jetty-specific solution. 我意识到答案已被接受,但不幸的是它依赖于Jetty特定的解决方案。 I haven't tried anything I'm about to suggest, but the first thing that comes to mind is to make use of Endpoint.setExecutor(Executor)
. 我没有尝试过任何我想提出的建议,但首先想到的是使用Endpoint.setExecutor(Executor)
。
One possibility is to create a ThreadFactory
that explicitly sets the uncaught exception handler for every thread it creates. 一种可能性是创建一个ThreadFactory
,它为它创建的每个线程显式设置未捕获的异常处理程序。 Guava's ThreadFactoryBuilder
can help: Guava的 ThreadFactoryBuilder
可以提供帮助:
public class MyHandler implements Thread.UncaughtExceptionHandler {
private final Endpoint endpoint;
public MyHandler(Endpoint endpoint) {
this.endpoint = endpoint;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
// ...
}
}
Endpoint endpoint = Endpoint.create(new MyServiceImpl());
Thread.UncaughtExceptionHandler handler = new MyHandler(endpoint);
ThreadFactory factory = new ThreadFactoryBuilder().setUncaughtExceptionHandler(handler).build();
Executor executor = Executors.newSingleThreadExecutor(factory);
endpoint.setExecutor(executor);
endpoint.publish("http://localhost:4425/myService");
Another possibility is to extend ThreadPoolExecutor
and override afterExecute(Runnable, Throwable)
. 另一种可能性是扩展ThreadPoolExecutor
并覆盖afterExecute(Runnable, Throwable)
。
public class ServiceExecutor extends ThreadPoolExecutor {
private final Endpoint endpoint;
// ThreadPoolExecutor has four ctors
public ServiceExecutor(Endpoint endpoint, ...) {
this.endpoint = endpoint;
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t != null) {
// ...
}
}
}
Endpoint endpoint = Endpoint.create(new MyServiceImpl());
Executor executor = new ServiceExecutor(endpoint, ...);
endpoint.setExecutor(executor);
endpoint.publish("http://localhost:4425/myService");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.