tomcat原理分析与简单实现

一、思路概述
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

[html]  view plain  copy
  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

[java]  view plain  copy
  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动态加载

[html]  view plain  copy
  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反映如下


四、注

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

猜你喜欢

转载自blog.csdn.net/weixin_38113189/article/details/79116901