簡單的Tomcat實現--2.4Tomcat的內建物件之Server
阿新 • • 發佈:2020-08-05
Server
-
Server是配置檔案中的頂層,一個Server代表的就是一個伺服器,在整個學習Tomcat內建物件的過程中,同意的做法都是藉助ServerXmlUtil這個類來將配置檔案中的資訊解析出來並構建物件,對映到類的例項當中。
-
Server類和上面的幾個類的改動不太一樣,因為已經說了Server代表的是伺服器,那麼在Bootstrap中的服務啟動和相應請求這些功能都應當放在Server中更為合理。
-
建立server類
-
package jerrymice.catalina; import cn.hutool.core.io.FileUtil; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.log.LogFactory; import cn.hutool.system.SystemUtil; import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; import jerrymice.http.Request; import jerrymice.http.Response; import jerrymice.util.Constant; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; /** * @author :xiaosong * @description:TODO * @date :2020/8/5 14:06 */ public class Server { private Service service; public Server(){ this.service = new Service(this); } public void start(){ logJvm(); init(); } private void logJvm() { // 建立一個Map用於儲存各種資訊 Map<String, String> infoMap = new LinkedHashMap<>(); infoMap.put("Server version", "JerryMice 1.0.0"); infoMap.put("Server build", "2020-08-03"); infoMap.put("OS:\t", SystemUtil.get("os.name")); infoMap.put("OS version", SystemUtil.get("os.version")); infoMap.put("Architecture", SystemUtil.get("os.arch")); infoMap.put("Java Home", SystemUtil.get("java.home")); infoMap.put("JSM Version", SystemUtil.get("java.runtime.version")); infoMap.put("JVM Vendor", SystemUtil.get("java.vm.specification.vendor")); Set<String> keys = infoMap.keySet(); for (String key : keys) { // 呼叫hutool的LogFactory工廠函式獲取logger,logger會自動根據log4j.properties來對Log4j的Logger進行配置 LogFactory.get().info(key + ":\t\t" + infoMap.get(key)); } } @SuppressWarnings("InfiniteLoopStatement") private void init(){ try { int port = 10086; ServerSocket serverSocket = new ServerSocket(port); while (true) { Socket socket = serverSocket.accept(); Runnable runnable = () -> { try { Request request = new Request(socket, service); Response response = new Response(); String uri = request.getUri(); if (null == uri){ return; } System.out.println("uri:" + uri); Context context = request.getContext(); if ("/".equals(uri)) { String html = "Hello, JerryMice"; response.getWriter().println(html); } else { String fileName = StrUtil.removePrefix(uri, "/"); File file = FileUtil.file(context.getDocBase(), fileName); if (file.exists()) { String fileContent = FileUtil.readUtf8String(file); response.getWriter().println(fileContent); if ("timeConsume.html".equals(fileName)) { ThreadUtil.sleep(1000); } } else { // 訪問檔案不存在的情況下 handle404(socket, uri); return; } } handle200(socket, response); }catch (IOException e) { LogFactory.get().info(e); }finally { // 將socket的關閉提取到最後,因為無論是200的響應還是404的響應都需要關閉socket try { socket.close(); }catch (IOException e){ LogFactory.get().info(e); } } }; jerrymice.util.ThreadUtil.run(runnable); } }catch (IOException e) { LogFactory.get().info(e); } } private static void handle200(Socket socket, Response response) throws IOException { // 獲取型別 String contentType = response.getContentType(); String headText = Constant.responseHead200; headText = StrUtil.format(headText, contentType); byte[] head = headText.getBytes(); // 獲取response中的html文字,這個html文字是通過writer寫到stringWriter字元流上的 byte[] body = response.getBody(); byte[] responseBytes = new byte[head.length + body.length]; ArrayUtil.copy(head, 0, responseBytes, 0, head.length); ArrayUtil.copy(body, 0, responseBytes, head.length, body.length); OutputStream outputStream = socket.getOutputStream(); outputStream.write(responseBytes); } }
-
-
將與啟動服務的方法都移動到server類中之後,Bootstrap變得異常簡潔。
-
public class Bootstrap { public static void main(String[] args) { Server server = new Server(); server.start(); } }
-