博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《深入剖析Tomcat》阅读(二)
阅读量:6692 次
发布时间:2019-06-25

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

   Tomcat是基于Sun公司标准的开源Servlet容器。

   Servlet是什么?

    Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

Servlet运行于支持Java的应用服务器中。从实现上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server。此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
Servlet编程需要使用到javax.servlet 和 javax.servlet.http两个包下面的类和接口,在所有的类和接口中,javax.servlet.servlet 接口最为重要。所有的servlet程序都必须实现该接口或者继承实现了该接口的类。

Servlet只是一种标准,按照这种标准既可以实现HTTP请求也可以实现其他的协议,用于执行Servlet的启动和管理程序称为Servlet容器,Tomcat便是一个很经常使用的Servlet容器。

上面一小节介绍了一个简单的HTTP的web服务器,是单线程的只能处理单个请求,请求处理完毕之后就重新开始准备接受连接的web服务器。

没有用到Servlet标准,只是简单的定义了Request和Response,简单解析了url以及将静态的文本文件通过输出流输出,并且我们发现response并没有http报文头,浏览器应该是针对这种情况做了特殊处理,比如直接打印流中的内容。

------------------------------------------------------------------------------------

一个功能齐全的Servlet容器有以下几件事情

1)第一次调用某个Servlet时,要载入该Servlet,并调用其init()方法,并且仅此一次

 

------------------------------------------------------------

下面举一个很简单的Servlet容器的例子

 

 

Constants.java

import java.io.File;//定义了访问静态资源的位置public class Constants{	public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";}

Constants类定义了静态finla WEB_ROOT,WEB_ROOT指定了该Servlet容器中使用PrimitiveServlet类和静态资源的位置。

HttpServer1一直等待HTTP请求,并且是单线程处理HTTP请求,直到等待到shut命令

与一种不同的是,此时将会在HttpServer1当中解析url,通过url判断寻找的是Servlet对象还是静态资源,然后分发到不同的处理过程。

都分别架构Request对象和Response对象传入

ServletProcessor1 和
StaticResourceProcessor的process方法当中,在方法当中回调Request和Response的相关方法

 

HttpServer1.java

import java.net.Socket;import java.net.ServerSocket;import java.net.InetAddress;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;public class HttpServer1{	/**	 * WEB_ROOT is the directory where our HTML and other files reside. For this	 * package, WEB_ROOT is the "webroot" directory under the working directory.	 * The working directory is the location in the file system from where the	 * java command was invoked.	 */	// shutdown command	private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";	// the shutdown command received	private boolean shutdown = false;	public static void main(String[] args)	{		HttpServer1 server = new HttpServer1();		server.await();	}	public void await()	{		ServerSocket serverSocket = null;		int port = 8080;		try		{			serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));		} catch (IOException e)		{			e.printStackTrace();			System.exit(1);		}		// Loop waiting for a request		while (!shutdown)		{			Socket socket = null;			InputStream input = null;			OutputStream output = null;			try			{				socket = serverSocket.accept();				input = socket.getInputStream();				output = socket.getOutputStream();				// create Request object and parse				Request request = new Request(input);				request.parse();				// create Response object				Response response = new Response(output);				response.setRequest(request);				// check if this is a request for a servlet or a static resource				// a request for a servlet begins with "/servlet/"				if (request.getUri().startsWith("/servlet/"))				{					ServletProcessor1 processor = new ServletProcessor1();					processor.process(request, response);				} else				{					StaticResourceProcessor processor = new StaticResourceProcessor();					processor.process(request, response);				}				// Close the socket				socket.close();				// check if the previous URI is a shutdown command				shutdown = request.getUri().equals(SHUTDOWN_COMMAND);			} catch (Exception e)			{				e.printStackTrace();				System.exit(1);			}		}	}}

Request.java

import java.io.InputStream;import java.io.IOException;import java.io.BufferedReader;import java.io.UnsupportedEncodingException;import java.util.Enumeration;import java.util.Locale;import java.util.Map;import javax.servlet.AsyncContext;import javax.servlet.DispatcherType;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class Request implements ServletRequest{	private InputStream input;	private String uri;	public Request(InputStream input)	{		this.input = input;	}	public String getUri()	{		return uri;	}	private String parseUri(String requestString)	{		int index1, index2;		index1 = requestString.indexOf(' ');		if (index1 != -1)		{			index2 = requestString.indexOf(' ', index1 + 1);			if (index2 > index1)				return requestString.substring(index1 + 1, index2);		}		return null;	}	public void parse()	{		// Read a set of characters from the socket		StringBuffer request = new StringBuffer(2048);		int i;		byte[] buffer = new byte[2048];		try		{			i = input.read(buffer);		} catch (IOException e)		{			e.printStackTrace();			i = -1;		}		for (int j = 0; j < i; j++)		{			request.append((char) buffer[j]);		}		System.out.print(request.toString());		uri = parseUri(request.toString());	}	/* implementation of the ServletRequest */	public Object getAttribute(String attribute)	{		return null;	}	public Enumeration getAttributeNames()	{		return null;	}	public String getRealPath(String path)	{		return null;	}	public RequestDispatcher getRequestDispatcher(String path)	{		return null;	}	public boolean isSecure()	{		return false;	}	public String getCharacterEncoding()	{		return null;	}	public int getContentLength()	{		return 0;	}	public String getContentType()	{		return null;	}	public ServletInputStream getInputStream() throws IOException	{		return null;	}	public Locale getLocale()	{		return null;	}	public Enumeration getLocales()	{		return null;	}	public String getParameter(String name)	{		return null;	}	public Map getParameterMap()	{		return null;	}	public Enumeration getParameterNames()	{		return null;	}	public String[] getParameterValues(String parameter)	{		return null;	}	public String getProtocol()	{		return null;	}	public BufferedReader getReader() throws IOException	{		return null;	}	public String getRemoteAddr()	{		return null;	}	public String getRemoteHost()	{		return null;	}	public String getScheme()	{		return null;	}	public String getServerName()	{		return null;	}	public int getServerPort()	{		return 0;	}	public void removeAttribute(String attribute)	{	}	public void setAttribute(String key, Object value)	{	}	public void setCharacterEncoding(String encoding) throws UnsupportedEncodingException	{	}	@Override	public int getRemotePort()	{		// TODO Auto-generated method stub		return 0;	}	@Override	public String getLocalName()	{		// TODO Auto-generated method stub		return null;	}	@Override	public String getLocalAddr()	{		// TODO Auto-generated method stub		return null;	}	@Override	public int getLocalPort()	{		// TODO Auto-generated method stub		return 0;	}	@Override	public ServletContext getServletContext()	{		// TODO Auto-generated method stub		return null;	}	@Override	public AsyncContext startAsync()	{		// TODO Auto-generated method stub		return null;	}	@Override	public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)	{		// TODO Auto-generated method stub		return null;	}	@Override	public boolean isAsyncStarted()	{		// TODO Auto-generated method stub		return false;	}	@Override	public boolean isAsyncSupported()	{		// TODO Auto-generated method stub		return false;	}	@Override	public AsyncContext getAsyncContext()	{		// TODO Auto-generated method stub		return null;	}	@Override	public DispatcherType getDispatcherType()	{		// TODO Auto-generated method stub		return null;	}}

Response.java

import java.io.OutputStream;import java.io.IOException;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.File;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletResponse;import javax.servlet.ServletOutputStream;public class Response implements ServletResponse{	private static final int BUFFER_SIZE = 1024;	Request request;	OutputStream output;	PrintWriter writer;	public Response(OutputStream output)	{		this.output = output;	}	public void setRequest(Request request)	{		this.request = request;	}	/* This method is used to serve a static page */	public void sendStaticResource() throws IOException	{		byte[] bytes = new byte[BUFFER_SIZE];		FileInputStream fis = null;		try		{			/* request.getUri has been replaced by request.getRequestURI */			File file = new File(Constants.WEB_ROOT, request.getUri());			fis = new FileInputStream(file);			/*			 * HTTP Response = Status-Line(( general-header | response-header |			 * entity-header ) CRLF) CRLF [ message-body ] Status-Line =			 * HTTP-Version SP Status-Code SP Reason-Phrase CRLF			 */			int ch = fis.read(bytes, 0, BUFFER_SIZE);			while (ch != -1)			{				output.write(bytes, 0, ch);				ch = fis.read(bytes, 0, BUFFER_SIZE);			}		} catch (FileNotFoundException e)		{			String errorMessage = "HTTP/1.1 404 File Not Found\r\n" + "Content-Type: text/html\r\n" + "Content-Length: 23\r\n" + "\r\n" + "

File Not Found

"; output.write(errorMessage.getBytes()); } finally { if (fis != null) fis.close(); } } /** implementation of ServletResponse */ public void flushBuffer() throws IOException { } public int getBufferSize() { return 0; } public String getCharacterEncoding() { return null; } public Locale getLocale() { return null; } public ServletOutputStream getOutputStream() throws IOException { return null; } public PrintWriter getWriter() throws IOException { // autoflush is true, println() will flush, // but print() will not. writer = new PrintWriter(output, true); return writer; } public boolean isCommitted() { return false; } public void reset() { } public void resetBuffer() { } public void setBufferSize(int size) { } public void setContentLength(int length) { } public void setContentType(String type) { } public void setLocale(Locale locale) { } @Override public String getContentType() { // TODO Auto-generated method stub return null; } @Override public void setCharacterEncoding(String charset) { // TODO Auto-generated method stub }}

ServletProcessor1.java

import java.net.URL;import java.net.URLClassLoader;import java.net.URLStreamHandler;import java.io.File;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class ServletProcessor1 {  public void process(Request request, Response response) {    String uri = request.getUri();    String servletName = uri.substring(uri.lastIndexOf("/") + 1);    URLClassLoader loader = null;    try {      // create a URLClassLoader      URL[] urls = new URL[1];      URLStreamHandler streamHandler = null;      File classPath = new File(Constants.WEB_ROOT);      // the forming of repository is taken from the createClassLoader method in      // org.apache.catalina.startup.ClassLoaderFactory      String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;      // the code for forming the URL is taken from the addRepository method in      // org.apache.catalina.loader.StandardClassLoader class.      urls[0] = new URL(null, repository, streamHandler);      loader = new URLClassLoader(urls);    }    catch (IOException e) {      System.out.println(e.toString() );    }    Class myClass = null;    try {      myClass = loader.loadClass(servletName);    }    catch (ClassNotFoundException e) {      System.out.println(e.toString());    }    Servlet servlet = null;    try {      servlet = (Servlet) myClass.newInstance();      servlet.service((ServletRequest) request, (ServletResponse) response);    }    catch (Exception e) {      System.out.println(e.toString());    }    catch (Throwable e) {      System.out.println(e.toString());    }  }}

  

import java.io.IOException;public class StaticResourceProcessor {  public void process(Request request, Response response) {    try {      response.sendStaticResource();    }    catch (IOException e) {      e.printStackTrace();    }  }}

  在静态资源的访问过程中,静态资源的的outpu过程放在了Response当中,其实是不合理的,应该放在Processor当中

 

 

---------------------------------------------------

private String parseUri(String requestString)

{
       int index1, index2;
       index1 = requestString.indexOf(' ');
       if (index1 != -1)
      {
            index2 = requestString.indexOf(' ', index1 + 1);
           if (index2 > index1)
                return requestString.substring(index1 + 1, index2);
       }
       return null;
}
Request类的parseURI的过程
利用了HTTP请求报文中的GET uri HTTP/1.1的规范找到第一行中间的uri字段

该资源是host后面的部分

比如www.baidu.com/guowuxin
则该字段便是/guowuxin
  

 

----------------------------------------------------------------------------------------------------------

下面讲一个这个程序的缺点

1:编程的OOP可能被破坏,封装性,传送给Servlet的ServletRequest对象本身应该
只能使用ServletRequest对象的相关方法,但是由于本身是子类Request对象,
所以如果认为进行强转,也是可以使用子类的方法的,破坏了封装性质,
不过这个问题可能出现在很多情景下,并不是一定要处理的额。

使用外观模式将这个类包起来就可以解决这个问题,

包接口的方法很类似于适配器模式,但是二者是不同的,
适配器模式是由于参数个数的不同或者方法名的不同而进行适配的,
这里是为了进一步的封装子类的方法。

 

package ex02.pyrmont;import java.io.IOException;import java.io.BufferedReader;import java.io.UnsupportedEncodingException;import java.util.Enumeration;import java.util.Locale;import java.util.Map;import javax.servlet.RequestDispatcher;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;public class RequestFacade implements ServletRequest {  private ServletRequest request = null;  public RequestFacade(Request request) {    this.request = request;  }  /* implementation of the ServletRequest*/  public Object getAttribute(String attribute) {    return request.getAttribute(attribute);  }  public Enumeration getAttributeNames() {    return request.getAttributeNames();  }  public String getRealPath(String path) {    return request.getRealPath(path);  }  public RequestDispatcher getRequestDispatcher(String path) {    return request.getRequestDispatcher(path);  }  public boolean isSecure() {    return request.isSecure();  }  public String getCharacterEncoding() {    return request.getCharacterEncoding();  }  public int getContentLength() {    return request.getContentLength();  }  public String getContentType() {    return request.getContentType();  }  public ServletInputStream getInputStream() throws IOException {    return request.getInputStream();  }  public Locale getLocale() {    return request.getLocale();  }  public Enumeration getLocales() {    return request.getLocales();  }  public String getParameter(String name) {    return request.getParameter(name);  }  public Map getParameterMap() {    return request.getParameterMap();  }  public Enumeration getParameterNames() {    return request.getParameterNames();  }  public String[] getParameterValues(String parameter) {    return request.getParameterValues(parameter);  }  public String getProtocol() {    return request.getProtocol();  }  public BufferedReader getReader() throws IOException {    return request.getReader();  }  public String getRemoteAddr() {    return request.getRemoteAddr();  }  public String getRemoteHost() {    return request.getRemoteHost();  }  public String getScheme() {   return request.getScheme();  }  public String getServerName() {    return request.getServerName();  }  public int getServerPort() {    return request.getServerPort();  }  public void removeAttribute(String attribute) {    request.removeAttribute(attribute);  }  public void setAttribute(String key, Object value) {    request.setAttribute(key, value);  }  public void setCharacterEncoding(String encoding)    throws UnsupportedEncodingException {    request.setCharacterEncoding(encoding);  }}

 

 

package ex02.pyrmont;import java.io.IOException;import java.io.PrintWriter;import java.util.Locale;import javax.servlet.ServletResponse;import javax.servlet.ServletOutputStream;public class ResponseFacade implements ServletResponse {  private ServletResponse response;  public ResponseFacade(Response response) {    this.response = response;  }  public void flushBuffer() throws IOException {    response.flushBuffer();  }  public int getBufferSize() {    return response.getBufferSize();  }  public String getCharacterEncoding() {    return response.getCharacterEncoding();  }  public Locale getLocale() {    return response.getLocale();  }  public ServletOutputStream getOutputStream() throws IOException {    return response.getOutputStream();  }  public PrintWriter getWriter() throws IOException {    return response.getWriter();  }  public boolean isCommitted() {    return response.isCommitted();  }  public void reset() {    response.reset();  }  public void resetBuffer() {    response.resetBuffer();  }  public void setBufferSize(int size) {    response.setBufferSize(size);  }  public void setContentLength(int length) {    response.setContentLength(length);  }  public void setContentType(String type) {    response.setContentType(type);  }  public void setLocale(Locale locale) {    response.setLocale(locale);  }}

 

package ex02.pyrmont;import java.net.Socket;import java.net.ServerSocket;import java.net.InetAddress;import java.io.InputStream;import java.io.OutputStream;import java.io.IOException;public class HttpServer2 {  // shutdown command  private static final String SHUTDOWN_COMMAND = "/SHUTDOWN";  // the shutdown command received  private boolean shutdown = false;  public static void main(String[] args) {    HttpServer2 server = new HttpServer2();    server.await();  }  public void await() {    ServerSocket serverSocket = null;    int port = 8080;    try {      serverSocket =  new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));    }    catch (IOException e) {      e.printStackTrace();      System.exit(1);    }    // Loop waiting for a request    while (!shutdown) {      Socket socket = null;      InputStream input = null;      OutputStream output = null;      try {        socket = serverSocket.accept();        input = socket.getInputStream();        output = socket.getOutputStream();        // create Request object and parse        Request request = new Request(input);        request.parse();        // create Response object        Response response = new Response(output);        response.setRequest(request);        //check if this is a request for a servlet or a static resource        //a request for a servlet begins with "/servlet/"        if (request.getUri().startsWith("/servlet/")) {          ServletProcessor2 processor = new ServletProcessor2();          processor.process(request, response);        }        else {          StaticResourceProcessor processor = new StaticResourceProcessor();          processor.process(request, response);        }        // Close the socket        socket.close();        //check if the previous URI is a shutdown command        shutdown = request.getUri().equals(SHUTDOWN_COMMAND);      }      catch (Exception e) {        e.printStackTrace();        System.exit(1);      }    }  }}

  

 

package ex02.pyrmont;import java.net.URL;import java.net.URLClassLoader;import java.net.URLStreamHandler;import java.io.File;import java.io.IOException;import javax.servlet.Servlet;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;public class ServletProcessor2 {  public void process(Request request, Response response) {    String uri = request.getUri();    String servletName = uri.substring(uri.lastIndexOf("/") + 1);    URLClassLoader loader = null;    try {      // create a URLClassLoader      URL[] urls = new URL[1];      URLStreamHandler streamHandler = null;      File classPath = new File(Constants.WEB_ROOT);      // the forming of repository is taken from the createClassLoader method in      // org.apache.catalina.startup.ClassLoaderFactory      String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;      // the code for forming the URL is taken from the addRepository method in      // org.apache.catalina.loader.StandardClassLoader class.      urls[0] = new URL(null, repository, streamHandler);      loader = new URLClassLoader(urls);    }    catch (IOException e) {      System.out.println(e.toString() );    }    Class myClass = null;    try {      myClass = loader.loadClass(servletName);    }    catch (ClassNotFoundException e) {      System.out.println(e.toString());    }    Servlet servlet = null;    RequestFacade requestFacade = new RequestFacade(request);    ResponseFacade responseFacade = new ResponseFacade(response);    try {      servlet = (Servlet) myClass.newInstance();      servlet.service((ServletRequest) requestFacade, (ServletResponse) responseFacade);    }    catch (Exception e) {      System.out.println(e.toString());    }    catch (Throwable e) {      System.out.println(e.toString());    }  }}

  

转载于:https://www.cnblogs.com/wuxinliulei/p/4899632.html

你可能感兴趣的文章
Zabbix 日志监控
查看>>
数据挖掘里的“降维”----从五阶魔方的玩法思考
查看>>
shell脚本实例之Charpter8-9
查看>>
Error polling connection 'qemu:///system': internal error Cannot find suitable emulator for
查看>>
iptables实战
查看>>
valgrind调试CPU缓存命中率和内存泄漏
查看>>
水星三维引擎发布2.0版本 ~友情帮介绍下~
查看>>
内外网访问NAT设置
查看>>
公开课视频-《第03章 部署-IT基础架构》-大企业云桌面部署实战-在线培训-视频(奉献)...
查看>>
数字方舟,末日起航-记2012云计算架构师峰会
查看>>
CocoStudio 1.4.0.1数据编辑器使用
查看>>
6425C-Lab3 管理用户与服务帐户(2)
查看>>
Linux系统工程师的必备素质
查看>>
第一个Symfony2的长期支持版释出(Symfony 2.3.0)
查看>>
与一位同学的聊天记录
查看>>
Postfix邮件系统安装配置视频
查看>>
  如何通过今日头条引精准流量,学完即用
查看>>
如何快速的提高自己:一切取决于你自己
查看>>
Linux 3.2中回写机制的变革
查看>>
组策略设置服务器俺去----设置登录提示
查看>>