最近做一个项目,需要动态添加与移除servlet容器的http端口,并且启动都是嵌入式的。因此,果断选择了Jetty。
在模块化方面,Jetty是做的相当给力的一个容器,对于端口的动态增删能力,动态启停等都来源于这种强大的模块化设计。
- 动态增删端口
一般在嵌入式Jetty中,都会通过一个handlerCollection来负责接收所有的接入请求。为了做到动态添加与移除的效果,做了如下权衡。
1.启动之初
启动之初,只将server启动,并且加入一个空的handlerCollection。此时,有一点要注意,
/* ------------------------------------------------------------ */
public HandlerCollection()
{
_mutableWhenRunning=false;
}
/* ------------------------------------------------------------ */
public HandlerCollection(boolean mutableWhenRunning)
{
_mutableWhenRunning=mutableWhenRunning;
}
无参构造函数默认的不允许在运行期间加入新的实例。因此,必须初始化填true。
private HandlerCollection handlers = new HandlerCollection(true);
2.动态加端口
List<Handler> handlerList = new LinkedList<>();
if (handlers.getHandlers() != null) {
for(Handler temp : handlers.getHandlers()) {
handlerList.add(temp);
}
}
MockHandler handler = new MockHandler(port, sysCode, mockDao);
handler.setServer(server);
handler.start();
handlerList.add(handler);
handlers.setHandlers(handlerList.toArray(new MockHandler[0]));
Connector connector = getConnector(port);
server.addConnector(connector);
connector.start();
private ServerConnector getConnector(int port) {
ServerConnector connector = new ServerConnector(server);
connector.setPort(port);
return connector;
}
每添加一个handler,必须先启动,让其先准备好,然后再替换之前的handler集合。
3.动态移除端口
for (Connector connector : server.getConnectors()) {
ServerConnector serverConnector = (ServerConnector) connector;
if (codePort == serverConnector.getPort()) {
connector.stop();
server.removeConnector(connector);
List<Handler> mockHandlers = new LinkedList<>();
for(Handler tempHandler : handlers.getHandlers()) {
MockHandler mockTempHandler = (MockHandler) tempHandler;
if (!mockTempHandler.getSysCode().equals(sysCode)) {
mockHandlers.add(tempHandler);
} else {
mockTempHandler.stop();
}
}
handlers.setHandlers(mockHandlers.toArray(new MockHandler[0]));
break;
} else {
continue;
}
}
移除之前,先要停止此handler工作,避免继续接入新的请求,但是处理者已经消失导致未知异常。
- 动态启停
关于动态启停,这归属于Jetty的嵌入式使用方式,有一点要注意的就是,启动Jetty将会hold住当前线程,因此可能需要一个独立线程来启动server。
@Override
public void destroy() throws Exception {
if (server != null) {
server.stop();
server.destroy();
}
}
@Override
public void afterPropertiesSet() throws Exception {
new Thread() {
@Override
public void run() {
server = new Server();
server.setHandler(handlers);
try {
server.start();
server.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}