上文书说道如何通过http协议建立一个静态的服务器来访问静态网页,但我们选择tomcat最主要的原因还是因为它能动态的执行servlet,这边文章将引导你实现一个能够运行servlet的服务器,这个简易的服务器符合tomcat的基本原理,但真的tomcat远不是这么简单,即使是15年前的tomcat4。

1.主程序逻辑分离

既然要实现动态的服务器,首先我们要实现模式的识别,在tomcat中,tomcat通过读取web.xml,在servlet的配置中通过url的模式来匹配servlet,我们这里当然不会这么复杂,我们暂且设置如下规则,如果你想访问一个servlet,那么你就在浏览器输入如localhost/servlet/TestServlet这样的地址,TestServlet是你servlet的名字,准确点来说就是你的servlet编译后的class的名称,当然你可以起你任意喜欢的名字

以上文为基础,将main方法中的静态处理改成如下

 if(request.getUri().startsWith("/servlet/"))
{
ServletProcessor processor=new ServletProcessor();
processor.process(request,response);
}else{
StaticResponseProcessor processor=new StaticResponseProcessor();
processor.process(request,response);
}

当request获得的uri以servlet开头,就去访问ServletProccess的方法.

2.ServletProccess

这个类的职责就是用于找到servlet并调用.不多说,先上代码

    public class ServletProcessor {
public void process(Request request,Response response)
{
String uri=request.getUri();
String servletName=uri.substring(uri.lastIndexOf("/")+1);
URLClassLoader loader=null;
try
{
URL[] urls=new URL[1];
URLStreamHandler streamHandler=null;
File classpath=new File(Constants.WEB_ROOT);
String repository=(new URL("file",null,
classpath.getCanonicalPath()+File.separator).toString());
System.out.println(repository);
urls[0] = new URL(null,repository,streamHandler);
loader=new URLClassLoader(urls);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Class myClass=null;
try{
myClass=loader.loadClass(servletName);
}catch (ClassNotFoundException e){
e.printStackTrace();
}
Servlet servlet=null; try{
servlet=(Servlet)myClass.newInstance();
servlet.service(request,response); }catch (Exception e){
System.out.println(e.toString());
}catch (Throwable t){
System.out.println(t.toString());
} }
}

首先,我们要找到这个类,这个类应该在哪呢,在tomcat中,这个类即class文件在/WEB-INF/classes下,我们暂且先直接放在webroot下面,负责记录存储位置的是一个专门的Constants类的静态变量

 public static final String WEB_ROOT=System.getProperty("user.dir")+File.separator+"webroot";

  程序使用一个URLClassLoader来加载这个class,为了禁止servlet访问tomcat中的类,tomcat自定义了一个加载器,这个问题以后再详细说明,加载完类之后,用newInstance实例化,按理说这里会先调用init方法,老规矩,先忽略了,然后调用servlet的service方法,这时候细心的你可能发现了,在servlet的方法中,我的request是实现了servletRequest接口的,同理还有response,但你的request是自己定义的,这么调用肯定是错的,而且说好的response.getWriter呢,下面我们来改造request和response

3.request,response

其实并不需要多少操作,只需要把request实现ServletRequest接口,response实现ServletResponse接口,然后使用IDE的代码补全,里面的方法先都空着好了,在response的getWriter添加如下代码

 public PrintWriter getWriter() throws IOException {
writer=new PrintWriter(output,true);
return writer;
}

4.facade

至此,这个动态服务器已经可以用了,但是不知道你有没有注意到另一个问题,我们在servlet使用的request是tomcat传给我们的,那也就是说我们可以把这个servletRequest向下转型为tomcat的request类,然后我们就可以访问request的parse()之类的方法,但显然tomcat是不容许的,tomcat在这里使用了外观模式新建一个类requestFacade,在构造函数中传入tomcat的request,实现所有外部能够访问的方法,在方法中调用request的相应的方法,这样就能完美的隐藏那些request的必须的且不应该被servlet访问的public方法.

5.结果

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("service");
res.getWriter().println("service");
}


地址:https://github.com/Asens/AsServer/tree/master/AsServerV1.0.1

下集预告:我会把接受请求和处理请求的逻辑分离,并引入线程池概念,是这个服务器能够同时处理多个请求

从零开始写一个Tomcat(贰)--建立动态服务器的更多相关文章

  1. 从零开始写一个Tomcat(叁)--请求解析

    挖坑挖了这么长时间也该继续填坑了,上文书讲到从零开始写一个Tomcat(贰)--建立动态服务器,讲了如何让服务器解析请求,分离servlet请求和静态资源请求,读取静态资源文件输出或是通过URLCla ...

  2. 从零开始写一个Tomcat(壹)

    Tomcat是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,也是一个servlet容器的优秀解决方案,做Java web开发的基本上都使用过,但是tomcat大多时间对于我们是一个黑 ...

  3. 从零开始写一个发送h264的rtsp服务器(上)

    转自:http://blog.csdn.net/jychen105/article/details/47006345 一.什么是RTSP 通常所说的rtsp协议其实包含三个协议: rtsp协议, rt ...

  4. 从零开始写一个发送h264的rtsp服务器(下)

    转自:http://blog.csdn.net/jychen105/article/details/47012099 一.H264是如何通过rtsp发送的 简单来说,H264就是通过打包到rtp协议的 ...

  5. 从零开始写一个武侠冒险游戏-7-用GPU提升性能(2)

    从零开始写一个武侠冒险游戏-7-用GPU提升性能(2) ----把地图处理放在GPU上 作者:FreeBlues 修订记录 2016.06.21 初稿完成. 2016.08.06 增加对 XCode ...

  6. 从零开始写一个武侠冒险游戏-0-开发框架Codea简介

    从零开始写一个武侠冒险游戏-0-开发框架Codea简介 作者:FreeBlues 修订记录 2016.06.21 初稿完成. 2016.08.03 增加对 XCode 项目文件的说明. 概述 本游戏全 ...

  7. 深入浅出React Native 3: 从零开始写一个Hello World

    这是深入浅出React Native的第三篇文章. 1. 环境配置 2. 我的第一个应用 将index.ios.js中的代码全部删掉,为什么要删掉呢?因为我们准备从零开始写一个应用~学习技术最好的方式 ...

  8. 从零开始写一个武侠冒险游戏-8-用GPU提升性能(3)

    从零开始写一个武侠冒险游戏-8-用GPU提升性能(3) ----解决因绘制雷达图导致的帧速下降问题 作者:FreeBlues 修订记录 2016.06.23 初稿完成. 2016.08.07 增加对 ...

  9. 一起学习造轮子(二):从零开始写一个Redux

    本文是一起学习造轮子系列的第二篇,本篇我们将从零开始写一个小巧完整的Redux,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Promises/A+,Red ...

随机推荐

  1. javascript基础学习(十五)

    javascript之cookie 学习要点: cookie介绍 创建与获取cookie cookie的编码 cookie的生存期 cookie的路径 cookie的domain cookie的sec ...

  2. Linux Chaining Operators用法学习

    Linux Chaining Operators顾名思义,就是连接命令的操作,有些时候,往往一些命令可以用一行命令代替,我们就不需要大动干戈再去写Shell Script了,掌握和学习这些Chaini ...

  3. C++ Primer 5th 第12章 动态内存

    练习12.1:在此代码的结尾,b1 和 b2 各包含多少个元素? StrBlob b1; { StrBlob b2 = {"a", "an", "th ...

  4. 百度上传插件WebUploader,angularjs指令封装

    1.WebUploader特点 官网地址:http://fex.baidu.com/webuploader/ 1.1 分片.并发 分片与并发结合,将一个大文件分割成多块,并发上传,极大地提高大文件的上 ...

  5. 初涉JavaScript模式 (2) : 基本技巧

    尽量少用全局变量 大量使用全局变量会导致的后果 全局变量创建以后会在整个JavaScript应用和Web页面中共享.所有的全局变量都存在于一个全局命名空间内,很容易发生冲突 不知不觉创建了全局变量 其 ...

  6. InstallShield安装包中集成第三方安装包的方案选择[转]

      我们在制作安装包时,有些情况下会涉及第三方安装的集成,这里将讨论如何调用安装第三方包,以及需要注意的事项. 第三方安装包的介质类型有很多,主要有:单独的一个Setup.exe,单独的一个msi包, ...

  7. oracle删除互相关联的记录

    今天遇到一个问题,在数据库中删除一条记录,但是在删除的时候报错了,报出该记录已经被其他子记录引用,想了好久不知道怎么做,后来发现报错提示信息中会提示删除该记录时影响了那个约束条件,于是思路出来了: 1 ...

  8. Github 上利用github pages 部署站点

    一:起始 准备项目,如果你在github上已有项目,则无需新建,如果你要新起一个项目,则需先在github上创建一个项目 本文以已创建好的 github/TestGitPage  为例. 二:设置gi ...

  9. tomcat jar包加载顺序

    加载顺序: 1. $java_home/lib 目录下的java核心api 2. $java_home/lib/ext 目录下的java扩展jar包 3. java -classpath/-Djava ...

  10. JDBC小结

    老师如是说:有一个规律永远不变,就是量变引起质变,什么时候你吃的盐比我吃的米多,那你就可以教我了…… 1.JDBC是一个标准,是J2EE的一部分:讲tcp时就提到了分层思想,jdbc也是分层,即上层只 ...