這裡的HttpServer,並不是哪裡專門下載的類庫了,而是在JDK1.6中內建的,在com.sun.net.httpserver包中,提供了簡單的較高層次意義上的Http ServerAPI,可以構建內建的HTTP Server,支援Http和Https協議,提供了HTTP1.1的部分實現,沒有被實現的那部分可以通過擴充已有的Http Server API來實現。程式員必須自己實現HttpHandler介面,HttpServer會調用HttpHandler實作類別的回調方法來處理用戶端請求,在這裡,我們把一個Http請求和它的響應稱為一個交換,封裝成HttpExchange類,HttpServer負責將HttpExchange傳給HttpHandler實作類別的回調方法. (摘過來的,也是官方的描述說明)
通過下面使用一個簡單的例子,就可以看到怎麼使用它們了,詳細的功能可以查看API文檔。訪問localhost:8086/ 和 localhost:8086/test看看
package com.test.myjava;import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.util.Queue;import java.util.concurrent.*;import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; public class HttpServerTest { public static void main(String[] args) {try {//允許最大串連數int backLog = 10;InetSocketAddress inetSock = new InetSocketAddress(8086);HttpServer httpServer = HttpServer.create(inetSock, backLog);//直接返回Hello.....httpServer.createContext("/", new HandlerTestA());//顯示已經處理的請求數,採用線程池httpServer.createContext("/test",new HandlerTestB());httpServer.setExecutor(null);httpServer.start();System.out.println("HttpServer Test Start!");} catch (Exception e) {e.printStackTrace();}}}//直接處理請求class HandlerTestA implements HttpHandler{public void handle(HttpExchange httpExchange) throws IOException {// TODO Auto-generated method stub//針對請求的處理部分 //返回請求響應時,遵循HTTP協議String responseString = "<font color='#ff0000'>Hello! This a HttpServer!</font>";//設定回應標頭httpExchange.sendResponseHeaders(200, responseString.length()); OutputStream os = httpExchange.getResponseBody(); os.write(responseString.getBytes()); os.close(); }}//線程池還不會用,簡略的使用了下,意思有點差距,後面在分析class HandlerTestB implements HttpHandler{private static int requestNum = 0; ThreadPoolExecutor threadPoolExecutor;HandlerTestB(){//兩個常線上程,最大3個 threadPoolExecutor = new ThreadPoolExecutor(2,3, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), new ThreadPoolExecutor.CallerRunsPolicy() );}public void handle(HttpExchange he) throws IOException {// TODO Auto-generated method stubif((getQueueSize(threadPoolExecutor.getQueue()))<2){RequestTasks rqt = new RequestTasks(he); threadPoolExecutor.execute(rqt);}else System.out.println("Please Wait!");}private synchronized int getQueueSize(Queue queue) { return queue.size(); } }//處理請求的任務class RequestTasks implements Runnable{static int processedNum = 0;HttpExchange httpExchange;RequestTasks(HttpExchange he){httpExchange = he;processedNum++;}public void run() {// TODO Auto-generated method stubSystem.out.println("ProcessedNum:" +processedNum);String responseString = "ProcessedNum:" + processedNum + "\n";try{httpExchange.sendResponseHeaders(200, responseString.length()); OutputStream os = httpExchange.getResponseBody(); os.write(responseString.getBytes()); os.close();//去掉注釋,看看只能響應兩個,有些問題//while(true);}catch (Exception e){e.printStackTrace();}}}
看這些的時候有個小插曲,當時看不懂既然有了createContext ( )方法中的實現HttpHandler介面的類來處理請求,為什麼又要有個setExecutor來設定管理線程的Executor,而且還要在start()方法之前;這時自己查看文檔的時候看到createContext(),start()方法都是抽象方法(當然HttpServer也是抽象類別),是怎麼調用的呢。在網上找到其源碼時,才發現,HttpServer的建立首先是通過create(InetSocketAddress addr, int backlog)這個靜態方法建立,這裡面是通過 HttpServerProvider(它也是抽象類別,其子類 sun.net.httpserver.DefaultHttpServerProvider中的createHttpServer)來建立的,其後在具體建立過程中則是new了一個 HttpServerImpl類的執行個體(這個只是一個封裝,具體實現是ServerImpl類來完成最後的HttpServer對象的產生);查看ServerImpl的實現,才知道setExecutor設定的是處理TCP連結請求的線程,而createContext 裡設定的是針對具體的請求進行處理的回調方法,而且可以通過設定調用多次createContext(),設定不同路徑採用不同或相同的處理方法。為什麼繞了這麼多,採用了什麼設計模式,我是還沒到那個高度,期待有人能給留言解說下;或者自己以後慢慢的體會吧。
後面再把這些東西合起來,想個大概的應用情境。
參考
實現Http Server的三種方法 http://lpn520.iteye.com/blog/781273