簡單的Tomcat實現--2.1Tomcat的內建物件之host
阿新 • • 發佈:2020-08-05
host
-
host的意思是虛擬主機,通常都是localhost,代表本機
-
在server.xml中新增host標籤
-
<?xml version="1.0" encoding="UTF-8"?> <Server> <Host name="localhost"> <Context path="/b" docBase="d:/Java/JavaProject/Jerrymice/webapps/b" /> </Host> </Server>
-
-
在ServerXmlUtil中新增方法解析xml配置檔案中的host標籤屬性name
-
public static String getHostName(){ String name = ""; try{ Document document = Jsoup.parse(Constant.serverXmlFile, "utf-8"); Element host = document.select("Host").first(); name = host.attr("name"); }catch(IOException e){ LogFactory.get().error(e); } return name; }
-
-
建立Host類,有兩個欄位,一個是name,一個是context,這裡的context就是將原本Bootrap中的移植過來
-
package jerrymice.catalina; import cn.hutool.log.LogFactory; import jerrymice.util.Constant; import jerrymice.util.ServerXmlUtil; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author :xiaosong * @description:TODO * @date :2020/8/4 22:16 */ public class Host { private String name; private Map<String, Context> contextMap; public Host(){ this.name = ServerXmlUtil.getHostName(); this.contextMap = new HashMap<>(); // 掃描資料夾內的所有應用 scanContextOnWebAppsFolder(); // 通過配置檔案server.xml掃描指定的應用 scanContextsByServerXml(); } public String getName(){ return name; } public void setName(String name){ this.name = name; } /** * 掃描webapp的根目錄,將所有的資料夾(應用)做成Context物件儲存在Map中 */ private void scanContextOnWebAppsFolder(){ LogFactory.get().info("Scanning webapps in webapps..."); File[] files = Constant.webappsFolder.listFiles(); if (files == null){ // 如果應用目錄下根本沒有應用,那就直接再見報告錯誤日誌 LogFactory.get().error(new NoSuchFieldError()); return; } for (File file : files){ if (!file.isDirectory()) { continue; } loadContext(file); } } private void loadContext(File folder) { // 對資料夾中的檔案進行解析, 獲取資料夾名 String path = folder.getName(); if ("ROOT".equals(path)) { // 如果是根目錄的話 path = "/"; } else { path = "/" + path; } String docBase = folder.getAbsolutePath(); // 建立Context物件用於儲存path和docBase Context context = new Context(path, docBase); // 將建立好的context放在Map中留待使用 contextMap.put(context.getPath(), context); } /** * 從server.xml檔案中獲取配置資訊 */ private void scanContextsByServerXml(){ LogFactory.get().info("Scanning webapps from server.xml..."); List<Context> contexts = ServerXmlUtil.getContext(); for (Context context: contexts){ contextMap.put(context.getPath(), context); } } /** * 通過path獲取其對飲的context */ public Context getContext(String path){ return contextMap.get(path); } }
-
-
Bootstrap的改動,將儲存Context的雜湊表移到Host類中之後,其對應的方法也一併移動,當服務啟動的時候,根據配置檔案建立一個Host物件。
-
package jerrymice; import jerrymice.catalina.Context; 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 jerrymice.catalina.Host; import jerrymice.http.Request; import jerrymice.http.Response; import jerrymice.util.Constant; import jerrymice.util.ServerXmlUtil; import sun.awt.windows.WPrinterJob; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.*; /** * @author :xiaosong * @description:專案的啟動類 * @date :2020/7/28 20:41 */ public class Bootstrap { /** * 定義伺服器的埠號 */ final static int PORT = 10086; public static void main(String[] args) { try { // 列印jvm資訊 logJvm(); // 在port埠上新建serverSocket ServerSocket serverSocket = new ServerSocket(PORT); // 建立host物件,host物件對於一個配置檔案來說是唯一的,所以在迴圈外建立 Host host = new Host(); // 外部使用一個while迴圈,當處理完一個Socket的連結請求之後,再處理下一個連結請求 while (true) { Socket socket = serverSocket.accept(); // 使用lambda表示式代替Runnable Runnable runnable = () -> { try { // 獲取輸入流,這個輸入流表示的是收到一個瀏覽器客戶端的請求 Request request = new Request(socket, host); System.out.println("瀏覽器的輸入資訊: \r\n" + request.getRequestString()); Response response = new Response(); // 先將html資訊寫入到response的Writer的StringWriter中 String uri; uri = request.getUri(); if (uri == null) { return; } Context context = request.getContext(); if ("/".equals(uri)) { String html = "Hello JerryMice"; response.getWriter().println(html); } else { // removePrefix()方法可以去掉字串指定的字首 String fileName = StrUtil.removePrefix(uri, "/"); File file = FileUtil.file(context.getDocBase(), fileName); if (file.exists()) { //如果檔案存在,那就去試圖訪問 String fileContent = FileUtil.readUtf8String(file); // 寫入到response中 response.getWriter().println(fileContent); // 判斷是否是模擬的耗時任務 if ("timeConsume.html".equals(fileName)) { ThreadUtil.sleep(1000); } } else { System.out.println("File not found!"); } } System.out.println(uri); // 開啟輸出流,準備給客戶端輸出資訊 handle200(socket, response); } catch (IOException e) { LogFactory.get().error(e); } }; jerrymice.util.ThreadUtil.run(runnable); } } catch (IOException e) { LogFactory.get().error(e); } } private static 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)); } } /** * @param socket: * @param response:Response物件,伺服器對瀏覽器請求的響應,可以通過response的getBody()獲取儲存在其中的html文字 * @throws IOException */ 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); socket.close(); } }
-