1. 程式人生 > 實用技巧 >簡單的Tomcat實現--2.4Tomcat的內建物件之Server

簡單的Tomcat實現--2.4Tomcat的內建物件之Server

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();
          }
      }