1. HttpServer
HttpServer作為http伺服器的server端:
public final class HttpServer {
private static final String IP = "127.0.0.1";
private static final int PORT = 9000;
private static final int BIZ_THREAD_SIZE = 100;
private static final Logger logger = LoggerFactory.getLogger(HttpServer.class);
public static void main(String[] args) throws Exception {
System.out.println("啟動Server...");
HttpServer.start();
}
public static void start() throws Exception {
initServerConfig();
// new NioEventLoopGroup()預設線程數為CPU核心數的兩倍(Runtime.getRuntime().availableProcessors() * 2),是以這裡不用額外指定。
EventLoopGroup bossGroup = new NioEventLoopGroup();
// 這裡worker不能使用預設,如果并發大的話需要增加線程數量
EventLoopGroup workerGroup = new NioEventLoopGroup(BIZ_THREAD_SIZE);
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
// ChannelOption.SO_BACKLOG對應的是tcp/ip協定listen函數中的backlog參數。函數listen(int socketfd, int backlog)用來初始化服務端可連接配接隊列。
// 服務端處理用戶端連接配接請求是順序處理的,是以同一時間隻能處理一個用戶端連接配接,多個用戶端來的時候,服務端将不能處理的用戶端連接配接請求放在隊列中等待處理,backlog參數指定了隊列的大小。
.option(ChannelOption.SO_BACKLOG, 1024)
.handler(new LoggingHandler(LogLevel.INFO))
.childOption(ChannelOption.SO_KEEPALIVE, true) // 子channel配置,保持長連接配接
.childHandler(new HttpServerInitializer());
// sync追蹤代碼可以得到:this.await(),實作阻塞
ChannelFuture channelFuture = bootstrap.bind(IP, PORT).sync();
// 啟動失敗則關閉線程組
if (!channelFuture.isSuccess()) {
shutdown(bossGroup, workerGroup);
throw new RuntimeException(channelFuture.cause());
}
channelFuture.channel().closeFuture().sync();
logger.info("bootstrap channel closed...");
} finally {
shutdown(bossGroup, workerGroup);
}
}
// 添加路徑映射和過濾器映射
private static void initServerConfig() {
ServerContext.setFilter(ServerContext.MAPPING_ALL, BaseFilter.class);
ServerContext.setFilter("/template", TemplateFilter.class);
ServerContext.setAction(ServerContext.MAPPING_ALL, DefaultIndexAction.class);
ServerContext.setAction("/template", TemplateAction.class);
ServerContext.setAction("/files", FileAction.class);
ServerContext.setROOT("root");
ServerContext.setPORT(8090);
}
private static void shutdown(EventLoopGroup bossGroup, EventLoopGroup workerGroup) {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
HttpServerInitializer設定http編解碼器,以及請求aggregator等:
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel socketChannel) {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline
//或者使用HttpRequestDecoder & HttpResponseEncoder
.addLast(new HttpServerCodec())
//把HttpObjectAggregator放入管道裡。HttpObjectAggregator會把多個消息轉換為一個單一的FullHttpRequest或是FullHttpResponse
.addLast(new HttpObjectAggregator(1024 * 1024))
//壓縮Http消息
// .addLast(new HttpChunkContentCompressor())
//大檔案支援,檔案上傳時使用
// .addLast(new ChunkedWriteHandler())
.addLast(new HttpServerExpectContinueHandler())
.addLast(new HttpServerDispatcherHandler());
}
}
入棧處理器,用于轉發http請求,類似于DispatcherServlet:
public class HttpServerDispatcherHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (!(msg instanceof FullHttpRequest)) {
return;
}
FullHttpRequest fullHttpRequest = (FullHttpRequest) msg;
final Request customerRequest = Request.build(ctx, fullHttpRequest);
final Response customerResponse = Response.build(ctx, customerRequest);
if (customerRequest.getRequestUrl().equals(HttpHelper.FAVICON_ICO)) {
return;
}
// 過濾器放行之後,執行action,實際處理業務邏輯
boolean passFilter = doFilter(customerRequest, customerResponse);
if (passFilter) {
doAction(customerRequest, customerResponse);
}
//如果發送請求未被觸發,則觸發之,否則跳過。
if(false == customerResponse.isSent()) {
customerResponse.response();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
/**
* 過濾器
* @param request
* @param response
* @return
*/
private boolean doFilter(Request request, Response response) {
//全局過濾器
Filter filter = ServerContext.getFilter(ServerContext.MAPPING_ALL);
if(null != filter) {
if(false == filter.doFilter(request, response)) {
return false;
}
}
//自定義過濾器
filter = ServerContext.getFilter(request.getRequestUrl());
if(null != filter) {
if(false == filter.doFilter(request, response)) {
return false;
}
}
return true;
}
/**
* 請求處理器
* 相當于servlet
* @param request
* @param response
*/
private void doAction(Request request, Response response) {
Action action = ServerContext.getAction(request.getRequestUrl());
if (null == action) {
//查找比對所有路徑的Action
action = ServerContext.getAction(ServerContext.MAPPING_ALL);
if(null == action) {
// 非Action方法,調用靜态檔案讀取
action = Singleton.get(FileAction.class);
}
}
action.doAction(request, response);
}
}
過濾器
public interface Filter {
/**
* 執行過濾
* @param request 請求對象
* @param response 響應對象
* @return 如果傳回true,則繼續執行下一步内容,否則中斷
*/
boolean doFilter(Request request, Response response);
}
過濾器示例:
public class TemplateFilter implements Filter {
@Override
public boolean doFilter(Request request, Response response) {
System.out.println("welcome in template filter...");
return true;
}
}
action
action用于實際處理業務,頂層接口:
public interface Action {
void doAction(Request request, Response response);
}
抽象Adapter:
public abstract class AbstractAction implements Action {
@Override
public void doAction(Request request, Response response) {
String method = request.getMethod();
if (HttpHelper.METHOD_GET.equals(method)) {
doGet(request, response);
} else if (HttpHelper.METHOD_POST.equals(method)) {
doPost(request, response);
} else if (HttpHelper.METHOD_PUT.equals(method)) {
doPut(request, response);
} else if (HttpHelper.METHOD_DELETE.equals(method)) {
doDelete(request, response);
} else if (HttpHelper.METHOD_HEAD.equals(method)) {
doHead(request, response);
} else if (HttpHelper.METHOD_OPTIONS.equals(method)) {
doOptions(request, response);
} else if (HttpHelper.METHOD_TRACE.equals(method)) {
doTrace(request, response);
}
}
protected void doGet(Request request, Response response) {}
protected void doPost(Request request, Response response) {}
protected void doPut(Request request, Response response) {}
protected void doDelete(Request request, Response response) {}
protected void doOptions(Request request, Response response) {}
protected void doHead(Request request, Response response) {}
protected void doTrace(Request request, Response response) {}
}
action示例:
public class TemplateAction extends AbstractAction {
@Override
protected void doGet(Request request, Response response) {
response.setContentType(HttpHelper.CONTENT_TYPE_JSON);
response.setContent("welcome in template action, do get...");
}
@Override
protected void doPost(Request request, Response response) {
response.setContent("welcome in template action, do post...");
}
}
。。。