我在Tomcat上运行应用程序。我使用Netty 4进行websocket处理。 Netty服务器在contextInitialized方法中的ServletContextListener中运行,并在contextDestroyed中停止。
这是我的Netty服务器类:
public class WebSocketServer {
private final int port;
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
private Channel serverChannel;
public WebSocketServer(int port) {
this.port = port;
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
}
public void run() throws Exception {
final ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new WebSocketServerInitializer());
serverChannel = b.bind(port).sync().channel();
System.out.println("Web socket server started at port " + port + '.');
System.out
.println("Open your browser and navigate to http://localhost:"
+ port + '/');
}
public void stop() {
if (serverChannel != null) {
ChannelFuture chFuture = serverChannel.close();
chFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
shutdownWorkers();
}
});
} else {
shutdownWorkers();
}
}
private void shutdownWorkers() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
运行后它的工作正常,但是当我尝试停止Tomcat时,我得到了异常:
信息:非法访问:此Web应用程序实例已经停止。无法加载io.netty.util.concurrent.DefaultPromise $ 3。最终跟随堆栈跟踪是由于为调试目的而抛出的错误以及尝试终止导致非法访问的线程引起的,并且没有功能影响。 java.lang.IllegalStateException 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1610) 在org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1569) 在io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:592) at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:403) at io.netty.util.concurrent.SingleThreadEventExecutor $ 2.run(SingleThreadEventExecutor.java:139) 在java.lang.Thread.run(Thread.java:662)
Tomcat挂机后。 可能是什么原因?
答案 0 :(得分:2)
我假设您从Servlet.destroy()某处调用shutdownWorkers()
或使用其他一些机制来确保服务器在servlet停止/卸载时关闭。
然后你需要做
void shutdownWorkers() {
Future fb = trbossGroup.shutdownGracefully();
Future fw = workerGroup.shutdownGracefully();
try {
fb.await();
fw.await();
} catch (InterruptedException ignore) {}
}
这是因为shutdownGracefully()
返回了一个Future,而且,在没有等待它的情况下,你会留下那些试图在非常紧张的环境中关闭连接的东西。首先启动所有关闭,然后等到期货可用,这也是有意义的,这样它就会并行运行并且发生得更快。
它为我解决了这个问题。显然,你可以在没有swallowing InterruptedException的情况下使你的系统更好,并用一个漂亮的方法包装每个调用,并为每个await()
设置合理的超时。一般来说运动很好,但实际上很可能你在代码中并不关心这一点。
旁注:是的,对于WebSockets,您最好使用Tomcat的本机,标准兼容且强大的实现。对于许多其他事情来说,Netty是非常棒的,但在这里它将是一个错误的工具。