我们如何实现一个手写的tomcat并处理动态的servlet请求?
一、思路分析
首先我们的tomcat是java语言实现的。那么可以思考一下迷你版的tomcat是怎么实现的,然后再来实现动态请求处理。
- tomcat的简单实现
1.1 tomcat既然能一直监听客户端的请求那么我们可以知道是在网络层面利用了Socket去实时监听虚拟主机的端口当一个http请求过来的时候会携带请求方式以及域名也就是虚拟主机还有参数等等我们通过Socket获取输入流,创建Request对象并把请求参数封装,比如请求方式、静态资源的url
- tomcat请求处理
2.1 既然我们想要去处理请求的能力,那么我们必须要有Response对象传入一个输出流来往外写数据从而来响应客户端的请求。然后对于客户端的请求我们可以用一个线程类来处理,创建一个线程池来管理请求线程,这是我们的主体思路
2.2 我们先思考对于前面的多个web项目部署在tomcat下面的目录结构是怎么样的,我们的web项目都是统一部署在webapp目录下面,它的路径是由tomcat的server.xml节点appBase来决定的,这样我们可以获取到项目的根路径也就是项目名称,进而我们可以根据每个项目的web.xml文件知道每个项目下的servlet全限定名与处理的对应url拦截,这样就可以封装三个相应的数据方便后面对客户端请求做出响应第一个map对象key为项目名value为我们的web.xml文件磁盘路径第二个map对象key为项目名value为class文件的list对象,在这一步我们完成了对服务器下部署的项目封装,一个请求过来了我们就可以作出相应的响应了
二、主要代码展示
1.解析tomcat的server.xml文件获取到的tomcat下所部署的所有web项目
//1 加载解析 server.xml文件
InputStream resourceAsStream = ResourcesLoad.class.getClassLoader().getResourceAsStream("conf/server.xml");
SAXReader saxReader = new SAXReader();
Document read = saxReader.read(resourceAsStream);
//获取跟路径
Element rootElement = read.getRootElement();
Document document = rootElement.getDocument();
//2 获取端口
Element node = (Element) document.selectSingleNode("//Connector");
port =Integer.valueOf(node.attributeValue("port"));
//3 获取host
Element element = (Element) document.selectSingleNode("//Host");
//虚拟主机
String localhost = element.attributeValue("name");
//虚拟主机
Host host = new Host();
host.setHostName(localhost);
List<Host>list = new ArrayList<>();
list.add(host);
engine.setHosts(list);
//部署的地址路径
String appBase = element.attributeValue("appBase");
//4 根据这个路径去解析里面的项目 映射端口和虚拟主机,项目,以及url->servlet
parseAppBase(appBase);
}
-
解析web项目部署路径appBase节点封装context对应资源
/** * 解析server.xml文件appBase * @param appBase */ private static void parseAppBase(String appBase) { File file=new File(appBase); File[] files = file.listFiles(); List<BaseContext> contextList = engine.getHosts().get(0).getContextList(); for (File file1 : files) { List<String> classList=new ArrayList<>(); String name = file1.getName(); contextList.add(new BaseContext(name)); doFile(file1.getPath(), name,classList); } } /** * 循环查找对应资源保存在map中 key为项目名字 value为资源路径 * @param path * @param name */ private s