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需要根据请求调用的方法,动态地加载方法所在的类,完成累的实例化并通过该实例获得需要的方法最终将请求
传入方法执行。
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
-
package cn.wwyxxmiemie.littletomcat;
-
-
import java.io.BufferedReader;
-
import java.io.IOException;
-
import java.io.InputStreamReader;
-
import java.lang.reflect.Constructor;
-
import java.lang.reflect.InvocationTargetException;
-
import java.lang.reflect.Method;
-
import java.net.ServerSocket;
-
import java.net.Socket;
-
-
import cn.wwyxxmiemie.littletomcat.exclass.ExClass;
-
import cn.wwyxxmiemie.littletomcat.util.ClintRequestBean;
-
-
/**
-
* 这是littletomcat的类,是整个容器的入口类
-
* 程序在这个类的main方法启动
-
* @author 卫卫羊习习
-
*/
-
public class Main {
-
-
/**
-
* 容器主方法
-
* @param args
-
* @throws InstantiationException
-
* @throws ClassNotFoundException
-
* @throws SecurityException
-
* @throws NoSuchMethodException
-
*/
-
public static void main(String[] args) throws InstantiationException {
-
System.out.println("little_tomcat_is_running!");
-
try {
-
ServerSocket serverSocket = new ServerSocket(80);
-
while (true) {
-
//服务器每接受一次请求,创建一个socket对象
-
Socket socket = serverSocket.accept();
-
BufferedReader bReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
-
String line = bReader.readLine();
-
if (!(null==line)) {
-
ClintRequestBean requestBean = new ClintRequestBean(line);
-
System.out.println("客户端请求:"+requestBean.toReadString());
-
System.out.println("请求参数[路径]:"+requestBean.getRequestParm().get("path"));
-
System.out.println("请求参数[参数表]:"+requestBean.getRequestParm().get("attrs"));
-
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
-
try {
-
classLoader.loadClass("cn.wwyxxmiemie.littletomcat.exclass.ExClass");
-
System.out.println("动态加载ExClass类--成功");
-
} catch (ClassNotFoundException e) {
-
e.printStackTrace();
-
System.out.println("动态加载ExClass类--失败");
-
}
-
Class<?> exClass = null;
-
try {
-
exClass = Class.forName("cn.wwyxxmiemie.littletomcat.exclass.ExClass");
-
System.out.println("动态初始化ExClass类--成功");
-
} catch (ClassNotFoundException e) {
-
e.printStackTrace();
-
System.out.println("动态初始化ExClass类--失败");
-
}
-
Method method;
-
try {
-
method = exClass.getMethod("test", null);
-
System.out.println("得到ExClass对象的"+method.getName()+"方法");
-
try {
-
System.out.println("执行ExClass对象的"+method.getName()+"方法");
-
method.invoke(exClass.newInstance(), null);
-
} catch (IllegalAccessException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
} catch (IllegalArgumentException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
} catch (InvocationTargetException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
} catch (NoSuchMethodException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
} catch (SecurityException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
}
-
bReader.close();
-
socket.close();
-
-
}
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
-
}
-
-
}
2.ClintRequestBean.Java
-
package cn.wwyxxmiemie.littletomcat.util;
-
-
import java.util.HashMap;
-
import java.util.Map;
-
-
/**
-
* 客户端请求实体
-
* 用于封装客户端的链接数据
-
* @author 卫卫羊习习
-
*/
-
public class ClintRequestBean {
-
//以一个请求举例:http://127.0.0.1/www/qqq/eee
-
private String protocol;//协议类型(eg:http)
-
private String protocolVersion;//协议版本(eg:1.1)
-
private String data;//请求数据(eg:/www/qqq/eee)
-
private String method;//请求方法:(eg:GET)
-
-
/**
-
* 客户端请求实体构造方法
-
* @param protocol 协议类型 (eg:http)
-
* @param protocolVersion 协议版本 (eg:1.1)
-
* @param data 请求数据 (eg:/www/qqq/eee)【必须以‘/’分隔】
-
* @param method 请求方法 (eg:GET)
-
*/
-
public ClintRequestBean(String protocol, String protocolVersion, String data, String method) {
-
super();
-
this.protocol = protocol;
-
this.protocolVersion = protocolVersion;
-
this.data = data;
-
this.method = method;
-
}
-
/**
-
* 客户端请求实体构造方法
-
* @param request 请求链接,一般针对一条完整的http链接
-
*/
-
public ClintRequestBean(String request){
-
super();
-
String [] requestString = request.split(" ");
-
this.method = requestString[0];
-
this.data = requestString[1];
-
String [] proAndVer = requestString[2].split("/");
-
this.protocol = proAndVer[0];
-
this.protocolVersion = proAndVer[1];
-
}
-
-
/**
-
* 转化为可读String用于分析请求
-
* @return
-
*/
-
public String toReadString(){
-
return "ClintRequestBean [protocol=" + protocol + ", protocolVersion=" + protocolVersion + ", data=" + data
-
+ ", method=" + method + "]";
-
}
-
-
/**
-
* 得到请求的参数
-
* @return map[请求路径|参数map]
-
*/
-
public Map<String, Object> getRequestParm(){
-
Map<String,Object> map = new HashMap<>();
-
String [] parms = data.split("\\?");
-
map.put("path", parms[0]);
-
Map<String, String> attrs = new HashMap<>();
-
String[] kvs = parms[1].split("&");
-
for (String string : kvs) {
-
String [] kv = string.split("=");
-
attrs.put(kv[0], kv[1]);
-
}
-
map.put("attrs", attrs);
-
return map;
-
}
-
-
public String getProtocol() {
-
return protocol;
-
}
-
public void setProtocol(String protocol) {
-
this.protocol = protocol;
-
}
-
public String getProtocolVersion() {
-
return protocolVersion;
-
}
-
public void setProtocolVersion(String protocolVersion) {
-
this.protocolVersion = protocolVersion;
-
}
-
public String getData() {
-
return data;
-
}
-
public void setData(String data) {
-
this.data = data;
-
}
-
public String getMethod() {
-
return method;
-
}
-
public void setMethod(String method) {
-
this.method = method;
-
}
-
@Override
-
public String toString() {
-
return this.method+" "+this.data+" "+this.protocol+"/"+this.protocolVersion;
-
}
-
-
}
3.ExClass.java 用于编译生成ExClass.class文件,供littletomcat动态加载
-
package cn.wwyxxmiemie.littletomcat.exclass;
-
-
/**
-
* 测试类,被主容器动态调用
-
* @author 卫卫羊习习
-
*/
-
public class ExClass {
-
/**
-
* 测试方法
-
*/
-
public void test(){
-
System.out.println("ExClass.test()方法被调用");
-
}
-
}
三、检测
在浏览器发出如下http请求
【http://127.0.0.1/qqq/www/eee/?a=1&b=2】
littletomcat反映如下
四、注
以上代码并没有实现选择方法,但类的加载实则参数为字符串,大家理解原理就好