博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Tomcat深入剖析学习02
阅读量:6786 次
发布时间:2019-06-26

本文共 19433 字,大约阅读时间需要 64 分钟。

Tomcat深入剖析学习02-实现一个简单的Servlet容器

一.什么是Servlet

  Servlet是sun公司提供的一门用于开发动态web资源的技术。

  Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
  1、编写一个Java类,实现servlet接口。
  2、把开发好的Java类部署到web服务器中。
  按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet

二.Servlet容器

  就是创建、管理servlet规范中相关对象、生命周期的应用程序。Tomcat就是一种Servlet容器。

三.相关类

  javax.servlet.Servlet接口

  所有Servlet类必须实现此Servlet接口,实现关于Servlet接口相关方法。这些方法如下:

    1.init():实例化某个servlet类后,容器调用对应的init方法进行初始化,该方法只会被调用一次;

    2.service():当servlet的一个客户端请求到达后,容器就开始调用对应servlet的service方法。同时需要传入参数servletRequest和servletResponse。

          从字面意思就能知道,servletRequest携带了客户端发送的HTTP请求的信息,而servletResponse则用于封装servlet的响应信息。

    3.destroy():当servlet实例调用完毕要被移除时,destroy方法将被调用。

    4.getServletConfig():该方法用于取得<servlet> <init-param>配置的参数

    5.getServletInfo():该方法提供有关servlet的信息,如作者、版本、版权。

  **其中1,2,3与Servlet类生命周期相关

四.本节应用程序实现类

    本节servlet容器程序包含六个类,与01节对比,HttpServer1主程序已经做了一些功能解耦,具体说明如下。

    1.HttpServer1:servlet容器核心程序,包括:主程序入口,服务器创建与启动,request/response创建,按请求uri调用不同的处理类

    2.Request:实现javax.servlet.ServletRequest接口,以及01节中自己实现的解析方法

    3.Response:实现javax.servlet.ServletResponse接口,

    4.StaticResourceProcessor:静态资源处理类,处理uri是静态资源的请求

    5.ServletProcessor1:Servlet处理类,处理uri形如/servlet/servletname的请求(动态资源请求)

    6.Constants:常量类,将01节中服务器的常量部分功能拆解出来,包含了文根信息。

    此外,既然是Servlet容器,我们还需定义一个Servlet类PrimitiveServlet实现Servlet接口。

 五.具体代码

    1.PrimitiveServlet:主要实现了init,service,destroy方法   

1 package com.liuwei.ServletServer1; 2  3 import java.io.IOException; 4 import java.io.PrintWriter; 5  6 import javax.servlet.Servlet; 7 import javax.servlet.ServletConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest;10 import javax.servlet.ServletResponse;11 12 /**13  * 14  * @author liuwei 15  * 继承了servlet接口,重写5个方法16  */17 public class PrimitiveServlet implements Servlet{18 19     @Override20     public void destroy() {21         System.out.println("destroy");22     }23 24     @Override25     public ServletConfig getServletConfig() {26         return null;27     }28 29     @Override30     public String getServletInfo() {31         return null;32     }33 34     @Override35     public void init(ServletConfig servletConfig) throws ServletException {36         System.out.println("init");37     }38    //service方法,浏览器显示相关信息39     @Override40     public void service(ServletRequest arg0, ServletResponse arg1)41             throws ServletException, IOException {42         System.out.println("from service");43         PrintWriter pw = arg1.getWriter();44         pw.println("this is primitiveServlet!");45     }46 47 }

  2.Request类:接口的类没有具体实现,保留了01节中的解析方法parse,parseuri

1 package com.liuwei.ServletServer1;  2   3 import java.io.BufferedReader;  4 import java.io.IOException;  5 import java.io.InputStream;  6 import java.io.UnsupportedEncodingException;  7 import java.util.Enumeration;  8 import java.util.Locale;  9 import java.util.Map; 10  11 import javax.servlet.AsyncContext; 12 import javax.servlet.DispatcherType; 13 import javax.servlet.RequestDispatcher; 14 import javax.servlet.ServletContext; 15 import javax.servlet.ServletInputStream; 16 import javax.servlet.ServletRequest; 17 import javax.servlet.ServletResponse; 18  19 //HTTP请求类 20 public class Request implements ServletRequest{ 21     //请求对象中的输入流对象 22     private InputStream input; 23      24     private String uri; 25     //构造函数 26     public Request(InputStream input){ 27         this.input = input; 28     } 29     //解析请求的函数 30     public void parse(){ 31         StringBuffer request = new StringBuffer(); 32         byte[] buffer = new byte[2038]; 33         int i=-1; 34         try{ 35             i = input.read(buffer); 36         }catch(Exception e){ 37             e.printStackTrace(); 38         } 39         for(int j=0;j
index1){ 52 return request.substring(index1+1,index2); 53 } 54 } 55 return null; 56 } 57 public String getUri(){ 58 return uri; 59 } 60 @Override 61 public AsyncContext getAsyncContext() { 62 // TODO Auto-generated method stub 63 return null; 64 } 65 @Override 66 public Object getAttribute(String arg0) { 67 // TODO Auto-generated method stub 68 return null; 69 } 70 @Override 71 public Enumeration
getAttributeNames() { 72 // TODO Auto-generated method stub 73 return null; 74 } 75 @Override 76 public String getCharacterEncoding() { 77 // TODO Auto-generated method stub 78 return null; 79 } 80 @Override 81 public int getContentLength() { 82 // TODO Auto-generated method stub 83 return 0; 84 } 85 @Override 86 public String getContentType() { 87 // TODO Auto-generated method stub 88 return null; 89 } 90 @Override 91 public DispatcherType getDispatcherType() { 92 // TODO Auto-generated method stub 93 return null; 94 } 95 @Override 96 public ServletInputStream getInputStream() throws IOException { 97 // TODO Auto-generated method stub 98 return null; 99 }100 @Override101 public String getLocalAddr() {102 // TODO Auto-generated method stub103 return null;104 }105 @Override106 public String getLocalName() {107 // TODO Auto-generated method stub108 return null;109 }110 @Override111 public int getLocalPort() {112 // TODO Auto-generated method stub113 return 0;114 }115 @Override116 public Locale getLocale() {117 // TODO Auto-generated method stub118 return null;119 }120 @Override121 public Enumeration
getLocales() {122 // TODO Auto-generated method stub123 return null;124 }125 @Override126 public String getParameter(String arg0) {127 // TODO Auto-generated method stub128 return null;129 }130 @Override131 public Map
getParameterMap() {132 // TODO Auto-generated method stub133 return null;134 }135 @Override136 public Enumeration
getParameterNames() {137 // TODO Auto-generated method stub138 return null;139 }140 @Override141 public String[] getParameterValues(String arg0) {142 // TODO Auto-generated method stub143 return null;144 }145 @Override146 public String getProtocol() {147 // TODO Auto-generated method stub148 return null;149 }150 @Override151 public BufferedReader getReader() throws IOException {152 // TODO Auto-generated method stub153 return null;154 }155 @Override156 public String getRealPath(String arg0) {157 // TODO Auto-generated method stub158 return null;159 }160 @Override161 public String getRemoteAddr() {162 // TODO Auto-generated method stub163 return null;164 }165 @Override166 public String getRemoteHost() {167 // TODO Auto-generated method stub168 return null;169 }170 @Override171 public int getRemotePort() {172 // TODO Auto-generated method stub173 return 0;174 }175 @Override176 public RequestDispatcher getRequestDispatcher(String arg0) {177 // TODO Auto-generated method stub178 return null;179 }180 @Override181 public String getScheme() {182 // TODO Auto-generated method stub183 return null;184 }185 @Override186 public String getServerName() {187 // TODO Auto-generated method stub188 return null;189 }190 @Override191 public int getServerPort() {192 // TODO Auto-generated method stub193 return 0;194 }195 @Override196 public ServletContext getServletContext() {197 // TODO Auto-generated method stub198 return null;199 }200 @Override201 public boolean isAsyncStarted() {202 // TODO Auto-generated method stub203 return false;204 }205 @Override206 public boolean isAsyncSupported() {207 // TODO Auto-generated method stub208 return false;209 }210 @Override211 public boolean isSecure() {212 // TODO Auto-generated method stub213 return false;214 }215 @Override216 public void removeAttribute(String arg0) {217 // TODO Auto-generated method stub218 219 }220 @Override221 public void setAttribute(String arg0, Object arg1) {222 // TODO Auto-generated method stub223 224 }225 @Override226 public void setCharacterEncoding(String arg0)227 throws UnsupportedEncodingException {228 // TODO Auto-generated method stub229 230 }231 @Override232 public AsyncContext startAsync() {233 // TODO Auto-generated method stub234 return null;235 }236 @Override237 public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) {238 // TODO Auto-generated method stub239 return null;240 }241 }

  3.Response类:

1 package com.liuwei.ServletServer1;  2   3 import java.io.File;  4 import java.io.FileInputStream;  5 import java.io.IOException;  6 import java.io.OutputStream;  7 import java.io.PrintWriter;  8 import java.util.Locale;  9  10 import javax.servlet.ServletOutputStream; 11 import javax.servlet.ServletResponse; 12  13 public class Response implements ServletResponse{ 14      15     private Request request; 16     public OutputStream output; 17     private static final int BufferLength = 1024; 18     private PrintWriter pw; 19      20     public Response(OutputStream output){ 21         this.output = output; 22     } 23     public void setRequest(Request request){ 24         this.request = request; 25     } 26     //发送静态资源方法 27     public void sendStaticResource() throws IOException { 28         byte[] buffer = new byte[BufferLength]; 29         FileInputStream fis = null; 30         try{ 31             //查找请求中资源是否在root文件夹中存在,存在则写到output中,未存在在output写404信息 32             File file = new File(Constants.WEB_ROOT,request.getUri()); 33             if(file.exists()){ 34                 fis = new FileInputStream(file); 35                 int num = fis.read(buffer,0,BufferLength); 36                 if(num!=-1){ 37                     output.write(buffer,0,num); 38                     fis.read(buffer,0,BufferLength); 39                 } 40             }else{ 41                 String errorMsg = "HTTP/1.1 404 File Not Found\r\n" + 42                                 "Content-Type:text/html\r\n" + 43                                 "Content-Length:23\r\n" + 44                                 "\r\n" + 45                                 "

File Not Found

"; 46 output.write(errorMsg.getBytes()); 47 } 48 }catch(Exception ex){ 49 ex.printStackTrace(); 50 }finally{ 51 if(null!=fis){ 52 fis.close(); 53 } 54 } 55 } 56 @Override 57 public void flushBuffer() throws IOException { 58 // TODO Auto-generated method stub 59 60 } 61 @Override 62 public int getBufferSize() { 63 // TODO Auto-generated method stub 64 return 0; 65 } 66 @Override 67 public String getCharacterEncoding() { 68 // TODO Auto-generated method stub 69 return null; 70 } 71 @Override 72 public String getContentType() { 73 // TODO Auto-generated method stub 74 return null; 75 } 76 @Override 77 public Locale getLocale() { 78 // TODO Auto-generated method stub 79 return null; 80 } 81 @Override 82 public ServletOutputStream getOutputStream() throws IOException { 83 // TODO Auto-generated method stub 84 return null; 85 } 86 @Override 87 public PrintWriter getWriter() throws IOException { 88 pw = new PrintWriter(output,true); 89 return pw; 90 } 91 @Override 92 public boolean isCommitted() { 93 // TODO Auto-generated method stub 94 return false; 95 } 96 @Override 97 public void reset() { 98 // TODO Auto-generated method stub 99 100 }101 @Override102 public void resetBuffer() {103 // TODO Auto-generated method stub104 105 }106 @Override107 public void setBufferSize(int arg0) {108 // TODO Auto-generated method stub109 110 }111 @Override112 public void setCharacterEncoding(String arg0) {113 // TODO Auto-generated method stub114 115 }116 @Override117 public void setContentLength(int arg0) {118 // TODO Auto-generated method stub119 120 }121 @Override122 public void setContentType(String arg0) {123 // TODO Auto-generated method stub124 125 }126 @Override127 public void setLocale(Locale arg0) {128 // TODO Auto-generated method stub129 130 }131 }
Response.java

  4.ServletProcessor类:负责根据请求uri创建对应的servlet类,初始化并调用其service方法,由此可见,对应请求来临时,才会加载对应类实例

1 package com.liuwei.ServletServer1; 2  3 import java.io.File; 4 import java.io.IOException; 5 import java.net.URL; 6 import java.net.URLClassLoader; 7 import java.net.URLStreamHandler; 8  9 import javax.servlet.Servlet;10 import javax.servlet.ServletRequest;11 import javax.servlet.ServletResponse;12 13 /**14  * servlet加载类15  * 处理uri形如/servlet/servletName请求16  * @author DELL17  *18  */19 public class ServletProcessor1 {20     //分析request中的uri,并用类加载器加载21     public void process(Request request, Response response){22         //解析uri中的servletName23         String uri = request.getUri();24         String servletName = "com.liuwei.ServletServer1."+uri.substring(uri.lastIndexOf('/')+1);25         URLClassLoader loader = null;26         try{27             //**创建类载入器loader28             URL[] urls = new URL[1];29             URLStreamHandler streamHandler = null;30             File classPath = new File(Constants.WEB_ROOT);31             //servlet容器中,类载入器查找servlet类的目录称为仓库(repository)32             String repository = (new URL("file",null,classPath.getCanonicalPath()+File.separator)).toString();33             urls[0] = new URL(null,repository,streamHandler);34             loader = new URLClassLoader(urls);35         }catch(IOException ex){36             ex.printStackTrace();37         }38         //载入对应的servlet类39         Class myClass = null;40         try{41             myClass = loader.loadClass(servletName);42         }catch(ClassNotFoundException ex){43             ex.printStackTrace();44         }45         //实例化载入的servlet类46         Servlet servlet = null;47         try{48             servlet = (Servlet)myClass.newInstance();49             servlet.service((ServletRequest)request, (ServletResponse)response);50         }catch(Exception e){51             System.out.println(e.toString());52         }catch(Throwable e){53             System.out.println(e.toString());54         }55     }56     57 }
ServletProcessor.java

  5.StaticResourceProcessor类:静态资源处理类

1 package com.liuwei.ServletServer1; 2  3 import java.io.IOException; 4  5 /** 6  * 静态资源处理类 7  * @author DELL 8  * 9  */10 public class StaticResourceProcessor {11     //实质还是调用了response的sendStaticResource方法12     public void process(Request request,Response response){13         try{14             response.sendStaticResource();15         }catch(IOException e){16             System.out.println(e.toString());17         }18     }19 }
StaticResourceProcessor

  6.Constants类:

1 package com.liuwei.ServletServer1; 2  3 import java.io.File; 4  5  6 public class Constants { 7     //服务器的web项目所在目录 8         public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot"; 9     //servlet所在地址10         public static final String SERVLET_ROOT = System.getProperty("user.dir") + File.separator + "webroot" +File.separator+"com"+File.separator+"liuwei"+File.separator+"ServletServer1";11 }
Constants.java

  7.HttpServer1类:核心容器

1 package com.liuwei.ServletServer1; 2  3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.OutputStream; 7 import java.net.InetAddress; 8 import java.net.ServerSocket; 9 import java.net.Socket;10 11 public class HttpServer1 {12 13     //shutdown command14     private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";15     16     //the shutdown command received17     private static boolean shutdown = false;18     19     public static void main(String[] args) {20         HttpServer1 server = new HttpServer1();21         server.await();22     }23     //服务器启动方法24     public void await(){25         ServerSocket serverSocket = null;26         int port = 8888;27         try{28             serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));29         }catch(IOException ex){30             ex.printStackTrace();31             System.exit(1);32         }33         //此处判断shutdown标志34         while(!shutdown){35             Socket socket = null;36             InputStream input = null;37             OutputStream output = null;38             try{39                 //阻塞式等待一个请求,并返回请求端的socket对象40                 socket = serverSocket.accept();41                 //获取socket对象中的输入输出流对象42                 input = socket.getInputStream();43                 output = socket.getOutputStream();44                 45                 //create request object and parse46                 Request request = new Request(input);47                 request.parse();48                 System.out.println(request.getUri());49                 50                 //create response object51                 Response response = new Response(output);52                 response.setRequest(request);53                 //response.sendStaticResource();54                 55                 //check if request is a servletRequest or a staticResourceRequest56                 //简单的http请求分发,分为servlet处理器和静态资源处理器57                 if(request.getUri().startsWith("/servlet/")){58                     ServletProcessor1 processor = new ServletProcessor1();59                     processor.process(request,response);60                 }else{61                     StaticResourceProcessor processor = new StaticResourceProcessor();62                     processor.process(request,response);63                 }64                 //socket close65                 socket.close();66                 67                 //check if requesturl is shutdown command68                 shutdown = request.getUri().equals(SHUTDOWN_COMMAND);69             }catch(Exception e){70                 e.printStackTrace();71                 continue;72             }73         }74     }75 }
HttpServer1.java

六.工作流程

如下图所示:

此时,02节实现的servlet容器仍然负责一系列核心流程,包括:程序入口,服务创建,请求-响应对象创建,处理类分发。

注意处理类分发是02节的servlet容器所多出来的部分,由于除了静态资源的处理,还要对servlet请求处理,容器按照不同的请求uri,调用了不同的处理类。

此时对比01节,将如下两部分解耦,服务器可访问常量保存在了特定类Constants,处理逻辑分别形成了2个类StaticResourceProcessor和ServletProcessor。是功能的第一次拆分解耦。

此处注意ServletProcessor类,它在第8步会自动根据请求uri加载对应的servlet类,并调用其service方法。如果我们把02这样一个简单的servlet容器提供出来,那么编程人员就可以编写不同的servlet类来实现自己的功能,返回对应的结果。这就是tomcat服务器的雏形。

转载于:https://www.cnblogs.com/liuweiblog/p/7148928.html

你可能感兴趣的文章
文本处理命令介绍
查看>>
Java中常用的几种排序算法
查看>>
分支3-CentOS6.5下 子域授权、请求转发 的教程
查看>>
Javascript 拖拽 放大镜
查看>>
利用PowerShell创建事件日志
查看>>
python光荣之路测试开发班list学习笔记
查看>>
【c#】Excel COM组件在.net程序中的使用
查看>>
python的一些细节(持续更新中)
查看>>
requests中 .text 和 .content区别
查看>>
自定义 java 加载器
查看>>
JavaScript删除数组重复元素的5个高效算法
查看>>
【SVN】setup SVN Server
查看>>
Powershell 提示错误:get-help about_signing 解决
查看>>
cisco 和 华为的设备如何设置命令不分页显示
查看>>
nethogs监控进程网络流量
查看>>
Win7下chm文件无法打开问题解决方法
查看>>
DDOS***类型以及iptables防范ddos脚本
查看>>
我的友情链接
查看>>
基于MVC+EasyUI的Web开发框架经验总结(9)--在Datagrid里面实现外键字段的转义操作...
查看>>
总结:Linux磁盘分区管理
查看>>