zoukankan      html  css  js  c++  java
  • tomcat原理分析与简单实现

    tomcat原理分析与简单实现

    https://blog.csdn.net/u014795347/article/details/52328221

    一、思路概述
    1.tomcat实际是运行在jvm中的一个进程。我们把它定义为【中间件】,顾名思义,他是一个在java项目与jvm之间的
    中间容器。我们的web项目没有入口方法(main方法),那么他是如何运行起来并为客户端返回数据的呢?
    2.web项目[就javaee而讲]的本质,是一大堆的资源文件和方法。其中没有main方法,意味着web项目中的方法不会自动
    运行起来。
    3.这样,我们想想也知道,我们把web项目部署进tomcat的webapp中的目的是很明确的,那就是希望tomcat去调用我们
    写好的方法去为客户端返回需要的资源和数据。
    4.tomcat可以运行起来,并调用我们写好的方法。那么,tomcat一定有一个main方法。
    5.对于tomcat而言,它并不知道我们会有什么样的方法,这些都只是在项目被部署进webapp下后才确定的,由此分析,
    必然用到了java的反射来实现类的动态加载、实例化、获取方法、调用方法。
    6.那么tomcat如何确定调用什么方法呢。这取却于客户端的请求,举个栗子:
    【http://127.0.0.1:8080/a/b/c.htm?a=1&b=2】这样的一个请求,通过http协议,使用GET方法在浏览器发往本机的8080端口,
    携带的参数包含两部分a.方法,包含此方法的路径【/a/b/c.htm】,这里的方法为c,以htm标注,/a/b代表路径
    这样可以允许在不同路径下存在同名方法,更可以唯一定位一个方法。b.参数,包含参数名和参数值【a=1&b=2】
    通过这样的方法,要调用哪个方法,以及需要什么参数,我们的tomcat一目了然。
    7.综上所述,我们有下面的总结:
    a.tomcat需要main方法启动。
    b.tomcat需要监听本机上的某个端口。
    c.tomcat需要抓取此端口上来自客户端的链接并获得请求调用的方法与参数。
    d.tomcat需要根据请求调用的方法,动态地加载方法所在的类,完成累的实例化并通过该实例获得需要的方法最终将请求
    传入方法执行。

    e.将结果返回给客户端(jsp/html页面、json/xml字符串)。

    二、模型实现
    1.Main.java

    1.  
      package cn.wwyxxmiemie.littletomcat;
    2.  
       
    3.  
      import java.io.BufferedReader;
    4.  
      import java.io.IOException;
    5.  
      import java.io.InputStreamReader;
    6.  
      import java.lang.reflect.Constructor;
    7.  
      import java.lang.reflect.InvocationTargetException;
    8.  
      import java.lang.reflect.Method;
    9.  
      import java.net.ServerSocket;
    10.  
      import java.net.Socket;
    11.  
       
    12.  
      import cn.wwyxxmiemie.littletomcat.exclass.ExClass;
    13.  
      import cn.wwyxxmiemie.littletomcat.util.ClintRequestBean;
    14.  
       
    15.  
      /**
    16.  
      * 这是littletomcat的类,是整个容器的入口类
    17.  
      * 程序在这个类的main方法启动
    18.  
      * @author 卫卫羊习习
    19.  
      */
    20.  
      public class Main {
    21.  
       
    22.  
      /**
    23.  
      * 容器主方法
    24.  
      * @param args
    25.  
      * @throws InstantiationException
    26.  
      * @throws ClassNotFoundException
    27.  
      * @throws SecurityException
    28.  
      * @throws NoSuchMethodException
    29.  
      */
    30.  
      public static void main(String[] args) throws InstantiationException {
    31.  
      System.out.println("little_tomcat_is_running!");
    32.  
      try {
    33.  
      ServerSocket serverSocket = new ServerSocket(80);
    34.  
      while (true) {
    35.  
      //服务器每接受一次请求,创建一个socket对象
    36.  
      Socket socket = serverSocket.accept();
    37.  
      BufferedReader bReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    38.  
      String line = bReader.readLine();
    39.  
      if (!(null==line)) {
    40.  
      ClintRequestBean requestBean = new ClintRequestBean(line);
    41.  
      System.out.println("客户端请求:"+requestBean.toReadString());
    42.  
      System.out.println("请求参数[路径]:"+requestBean.getRequestParm().get("path"));
    43.  
      System.out.println("请求参数[参数表]:"+requestBean.getRequestParm().get("attrs"));
    44.  
      ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    45.  
      try {
    46.  
      classLoader.loadClass("cn.wwyxxmiemie.littletomcat.exclass.ExClass");
    47.  
      System.out.println("动态加载ExClass类--成功");
    48.  
      } catch (ClassNotFoundException e) {
    49.  
      e.printStackTrace();
    50.  
      System.out.println("动态加载ExClass类--失败");
    51.  
      }
    52.  
      Class<?> exClass = null;
    53.  
      try {
    54.  
      exClass = Class.forName("cn.wwyxxmiemie.littletomcat.exclass.ExClass");
    55.  
      System.out.println("动态初始化ExClass类--成功");
    56.  
      } catch (ClassNotFoundException e) {
    57.  
      e.printStackTrace();
    58.  
      System.out.println("动态初始化ExClass类--失败");
    59.  
      }
    60.  
      Method method;
    61.  
      try {
    62.  
      method = exClass.getMethod("test", null);
    63.  
      System.out.println("得到ExClass对象的"+method.getName()+"方法");
    64.  
      try {
    65.  
      System.out.println("执行ExClass对象的"+method.getName()+"方法");
    66.  
      method.invoke(exClass.newInstance(), null);
    67.  
      } catch (IllegalAccessException e) {
    68.  
      // TODO Auto-generated catch block
    69.  
      e.printStackTrace();
    70.  
      } catch (IllegalArgumentException e) {
    71.  
      // TODO Auto-generated catch block
    72.  
      e.printStackTrace();
    73.  
      } catch (InvocationTargetException e) {
    74.  
      // TODO Auto-generated catch block
    75.  
      e.printStackTrace();
    76.  
      }
    77.  
      } catch (NoSuchMethodException e) {
    78.  
      // TODO Auto-generated catch block
    79.  
      e.printStackTrace();
    80.  
      } catch (SecurityException e) {
    81.  
      // TODO Auto-generated catch block
    82.  
      e.printStackTrace();
    83.  
      }
    84.  
      }
    85.  
      bReader.close();
    86.  
      socket.close();
    87.  
       
    88.  
      }
    89.  
      } catch (IOException e) {
    90.  
      e.printStackTrace();
    91.  
      }
    92.  
       
    93.  
      }
    94.  
       
    95.  
      }

    2.ClintRequestBean.Java
    1.  
      package cn.wwyxxmiemie.littletomcat.util;
    2.  
       
    3.  
      import java.util.HashMap;
    4.  
      import java.util.Map;
    5.  
       
    6.  
      /**
    7.  
      * 客户端请求实体
    8.  
      * 用于封装客户端的链接数据
    9.  
      * @author 卫卫羊习习
    10.  
      */
    11.  
      public class ClintRequestBean {
    12.  
      //以一个请求举例:http://127.0.0.1/www/qqq/eee
    13.  
      private String protocol;//协议类型(eg:http)
    14.  
      private String protocolVersion;//协议版本(eg:1.1)
    15.  
      private String data;//请求数据(eg:/www/qqq/eee)
    16.  
      private String method;//请求方法:(eg:GET)
    17.  
       
    18.  
      /**
    19.  
      * 客户端请求实体构造方法
    20.  
      * @param protocol 协议类型 (eg:http)
    21.  
      * @param protocolVersion 协议版本 (eg:1.1)
    22.  
      * @param data 请求数据 (eg:/www/qqq/eee)【必须以‘/’分隔】
    23.  
      * @param method 请求方法 (eg:GET)
    24.  
      */
    25.  
      public ClintRequestBean(String protocol, String protocolVersion, String data, String method) {
    26.  
      super();
    27.  
      this.protocol = protocol;
    28.  
      this.protocolVersion = protocolVersion;
    29.  
      this.data = data;
    30.  
      this.method = method;
    31.  
      }
    32.  
      /**
    33.  
      * 客户端请求实体构造方法
    34.  
      * @param request 请求链接,一般针对一条完整的http链接
    35.  
      */
    36.  
      public ClintRequestBean(String request){
    37.  
      super();
    38.  
      String [] requestString = request.split(" ");
    39.  
      this.method = requestString[0];
    40.  
      this.data = requestString[1];
    41.  
      String [] proAndVer = requestString[2].split("/");
    42.  
      this.protocol = proAndVer[0];
    43.  
      this.protocolVersion = proAndVer[1];
    44.  
      }
    45.  
       
    46.  
      /**
    47.  
      * 转化为可读String用于分析请求
    48.  
      * @return
    49.  
      */
    50.  
      public String toReadString(){
    51.  
      return "ClintRequestBean [protocol=" + protocol + ", protocolVersion=" + protocolVersion + ", data=" + data
    52.  
      + ", method=" + method + "]";
    53.  
      }
    54.  
       
    55.  
      /**
    56.  
      * 得到请求的参数
    57.  
      * @return map[请求路径|参数map]
    58.  
      */
    59.  
      public Map<String, Object> getRequestParm(){
    60.  
      Map<String,Object> map = new HashMap<>();
    61.  
      String [] parms = data.split("\?");
    62.  
      map.put("path", parms[0]);
    63.  
      Map<String, String> attrs = new HashMap<>();
    64.  
      String[] kvs = parms[1].split("&");
    65.  
      for (String string : kvs) {
    66.  
      String [] kv = string.split("=");
    67.  
      attrs.put(kv[0], kv[1]);
    68.  
      }
    69.  
      map.put("attrs", attrs);
    70.  
      return map;
    71.  
      }
    72.  
       
    73.  
      public String getProtocol() {
    74.  
      return protocol;
    75.  
      }
    76.  
      public void setProtocol(String protocol) {
    77.  
      this.protocol = protocol;
    78.  
      }
    79.  
      public String getProtocolVersion() {
    80.  
      return protocolVersion;
    81.  
      }
    82.  
      public void setProtocolVersion(String protocolVersion) {
    83.  
      this.protocolVersion = protocolVersion;
    84.  
      }
    85.  
      public String getData() {
    86.  
      return data;
    87.  
      }
    88.  
      public void setData(String data) {
    89.  
      this.data = data;
    90.  
      }
    91.  
      public String getMethod() {
    92.  
      return method;
    93.  
      }
    94.  
      public void setMethod(String method) {
    95.  
      this.method = method;
    96.  
      }
    97.  
      @Override
    98.  
      public String toString() {
    99.  
      return this.method+" "+this.data+" "+this.protocol+"/"+this.protocolVersion;
    100.  
      }
    101.  
       
    102.  
      }

    3.ExClass.java 用于编译生成ExClass.class文件,供littletomcat动态加载
    1.  
      package cn.wwyxxmiemie.littletomcat.exclass;
    2.  
       
    3.  
      /**
    4.  
      * 测试类,被主容器动态调用
    5.  
      * @author 卫卫羊习习
    6.  
      */
    7.  
      public class ExClass {
    8.  
      /**
    9.  
      * 测试方法
    10.  
      */
    11.  
      public void test(){
    12.  
      System.out.println("ExClass.test()方法被调用");
    13.  
      }
    14.  
      }

    三、检测

    在浏览器发出如下http请求

    【http://127.0.0.1/qqq/www/eee/?a=1&b=2】

    littletomcat反映如下

    四、注

    以上代码并没有实现选择方法,但类的加载实则参数为字符串,大家理解原理就好

  • 相关阅读:
    常见算法之17---二叉树相等判断以及二叉树的复制
    常见算法之16---二维数组中查找元素
    常见算法之15---求N!末尾有多少个0
    常见算法之14---球放入盒问题
    常见算法之13---跳台阶问题
    常见算法之12---求a^n%p
    DB与java的关联
    重拾python
    Codeforces Round 212 Div 2 报告(以前没写完,现在也没心情补了,先就这样吧)
    交换Ctrl和Caps Lock键
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/10593079.html
Copyright © 2011-2022 走看看