tomcat原理分析与简单实现

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

2016年08月26日 14:48:18 卫卫羊习习 阅读数:4565
 
一、思路概述
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反映如下

四、注

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

tomcat原理分析与简单实现的更多相关文章

  1. Shiro框架 (原理分析与简单实现)

    Shiro框架(原理分析与简单实现) 有兴趣的同学也可以阅读我之前分享的:Java权限管理(授权与认证)CRM权限管理   (PS : 这篇博客里面的实现方式没有使用框架,完全是手写的授权与认证,可以 ...

  2. vue2.0 双向绑定原理分析及简单实现

    Vue用了有一段时间了,每当有人问到Vue双向绑定是怎么回事的时候,总是不能给大家解释的很清楚,正好最近有时间把它梳理一下,让自己理解的更清楚,下次有人问我的时候,可以侃侃而谈. 一.首先介绍Obje ...

  3. spring之mvc原理分析及简单模拟实现

    在之前的一篇博客中已经简单的实现了spring的IOC和DI功能,本文将在之前的基础上实现mvc功能. 一 什么是MVC MVC简单的说就是一种软件实现的设计模式,将整个系统进行分层,M(model ...

  4. Xss漏洞原理分析及简单的讲解

    感觉百度百科 针对XSS的讲解,挺不错的,转载一下~   XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XS ...

  5. Tomcat源码分析——请求原理分析(下)

    前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在& ...

  6. Tomcat源码分析——请求原理分析(中)

    前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...

  7. Tomcat源码分析——请求原理分析(上)

    前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程 ...

  8. tomcat原理解析(一):一个简单的实现

    tomcat原理解析(一):一个简单的实现 https://blog.csdn.net/qiangcai/article/details/60583330 2017年03月07日 09:54:27 逆 ...

  9. Servlet过滤器介绍之原理分析

    zhangjunhd 的BLOG     写留言去学院学习发消息 加友情链接进家园 加好友 博客统计信息 51CTO博客之星 用户名:zhangjunhd 文章数:110 评论数:858 访问量:19 ...

随机推荐

  1. .NET 中使用 Mutex 进行跨越进程边界的同步

    Mutex 是 Mutual Exclusion 的缩写,是互斥锁,用于防止两个线程同时对计算机上的同一个资源进行访问.不过相比于其他互斥的方式,Mutex 能够跨越线程边界. 本文内容 Mutex ...

  2. hdu2064

    hdu2064 汉诺塔变形,数学题 #include<stdio.h> ]; int main(){ A[]=; int i; ;i<=;i++){ A[i]=*A[i-]+; } ...

  3. java安全性-引用-分层-解耦

    Java不支持指针, 一切对内存的访问都必须通过对象的实例变量来实现,这样就防止程序员使用 "特洛伊"木马等欺骗手段访问对象的私有成员 访问一个对象必须通过这个对象的引用 java ...

  4. 我的nginx iis 负载均衡学习(环境搭建)

    1,下载并安装nginx 比较简单 2,进行网站的配置 我使用了我的IIS 站点中已经拥有的两个站点 3,进行nginx 的配置 配置如下: 在server 节点之前添加如下的配置: upstream ...

  5. ubuntu 14.04安装OVS虚拟OpenFlow交换机配置总结

    一.安装OVS sudo apt-get install openvswitch-controller openvswitch-switch openvswitch-datapath-source ( ...

  6. java中原子操作的实现分析

    一.CAS原理: CAS的全程即Compare And Swap,翻译成中文为比较并交换: CAS操作依赖于CPU指令CMPXCHG来实现比较并交换操作的原子性,通过查看HotSpot源码如下: 可以 ...

  7. jvm 知识点

    双亲委派模型的工作流程是: 如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中, ...

  8. JavaScriptSerializer类 对象序列化为JSON,JSON反序列化为对象 。

    JavaScriptSerializer 类由异步通信层内部使用,用于序列化和反序列化在浏览器和 Web 服务器之间传递的数据.说白了就是能够直接将一个C#对象传送到前台页面成为javascript对 ...

  9. Microsoft Dynamics CRM 如何修改域密码

    一.安装IIS6脚本工具,如下图所示: 二.复制iisadmpwd文件夹到AD Server的C:\Windows\SysWOW64\inetsrv文件夹下 三.注册Iisadmpwd目录下的IISp ...

  10. java jni 调用c++ opencv代码成功范例

    java上建立接口定义 package com.dtk; public class Rec { public native String RecImage(String src); public st ...