• servlet容器的职责

总的来说,一个全功能的servlet容器会为servlet的每个HTTP请求做下面的一些工作:

1,当第一次调用servlet的时候,加载该servlet类并调用servlet的init方法,只有一次,

2,对于每次请求,都要new出一个request请求和response相应实例,

3,调用servlet的service方法,同时传递ServletRequest和ServletResponse对象,

4,当servlet类被关闭的时候,调用servlet的destroy方法写在servlet类。





现在我自己模拟实现了一个最简单的tomcat,除了上面的第1点和第4点,基本的功能还是实现了,代码如下:

package linkin;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket; 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);
}
}
}
}
package linkin;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
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 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 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 String getLocalAddr()
{
return null;
} @Override
public String getLocalName()
{
return null;
} @Override
public int getLocalPort()
{
return 0;
} @Override
public int getRemotePort()
{
return 0;
}
}
package linkin;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Locale; import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse; public class Response implements ServletResponse
{
private static final int BUFFER_SIZE = 1024;
public static final String WEB_ROOT = System.getProperty("user.dir") + File.separator + "webroot";
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 static pages */
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(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" + "<h1>File Not Found</h1>";
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)
{
} @Override
public void setLocale(Locale locale)
{
} @Override
public String getContentType()
{
return null;
} @Override
public void setCharacterEncoding(String arg0)
{ } }
package linkin;

import java.io.IOException;

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

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
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(Response.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.
urls[0] = new URL(null, repository, streamHandler);
loader = new URLClassLoader(urls);
}
catch (IOException e)
{
System.out.println(e.toString());
}
Class myClass = null;
try
{
System.out.println(servletName);
myClass = loader.loadClass(servletName);
}
catch (ClassNotFoundException e)
{
System.out.println(e.toString());
}
Servlet servlet = null;
try
{
//跑一下反射,初始化一个实例,然后调用这个servlet的service方法。
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());
}
}
}
package linkin;

import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class PrimitiveServlet implements Servlet
{
@Override
public void init(ServletConfig config) throws ServletException
{
System.out.println("init");
} @Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
{
System.out.println("from service");
PrintWriter out = response.getWriter();
out.println("<html><head><title>linkin.html</title>"+
"<meta http-equiv=\"keywords\" content=\"keyword1,keyword2,keyword3\">"+
"<meta http-equiv='description' content='this is my page'>"+
"<meta http-equiv='content-type' content='text/html; charset=UTF-8'>"+
"<!--<link rel='stylesheet' type='text/css' href='./styles.css'>-->"+
"</head><h1>NightWish,气质在作祟。。。</h1><br></body></html>");
out.println("值得注意的是,要是去web应用去找一个文件那么直接指定物理路径找就好了,要是用类加载加载一个class文件,是要在classpath里面去找的");
out.println("现在一般不需要配置java的classpath了,默认情况就是当前的工作路径,也就是这个项目的bin下面的路径,在类加载找这个文件的时候一定要写上包名");
} public void destroy()
{
System.out.println("destroy");
} public String getServletInfo()
{
return null;
} public ServletConfig getServletConfig()
{
return null;
} }





补充说明:

首先先看上面的servlet的处理器里面调用servlet的service方法这2行代码:

try {
servlet = (Servlet) myClass.newInstance();
servlet.service((ServletRequest) request,(ServletResponse) response);
}

这里有一个问题:我们写的这个处理器并不是说只能接受servlet的请求,所以这里我们传入的参数就是request和response类型的,但是我们现在在调用servlet的时候,又要传入servletRequest和servletResponse类型的参数,这里向下强转是很危险的,万一人家这个请求和相应不是servlet类型的呢,对吧,所以我们就是要达到一种效果就是说:我贴出的这request和response这2块代码呢只能在我们自己的类里面使用,在我自己的包下面使用,在其他的地方不能被访问到,这样子我就随便向下转保证肯定不会出错了,而且也可以保证这2个类里面的方法也是安全的了,比如说外部的类肯定不能调用request的parseURI方法了,怎么办呢?一共有2种实现方式:

1,让上面的request类和response类拥有默认的访问权限,也就是说只能在自己的包中被访问到,那么这样子就安全了

2,使用门面设计模式,具体的讲解请查看我设计模式里面的那篇文章。大致的意思就是在上面的request和response外面再自己封装一次门面,将这个request和response私有化,里面所有的方法呢其实还是用这个request和response类来调用,这样子的话包外面就不能直接访问到request和response这2个类了。代码如下:



package linkin;

import java.io.BufferedReader;
import java.io.IOException;
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();
} ......................
}





自己模拟的一个简单的tomcat的更多相关文章

  1. 自己模拟的一个简单的web服务器

    首先我为大家推荐一本书:How Tomcat Works.这本书讲的很详细的,虽然实际开发中我们并不会自己去写一个tomcat,但是对于了解Tomcat是如何工作的还是很有必要的. Servlet容器 ...

  2. Linux——模拟实现一个简单的shell(带重定向)

    进程的相关知识是操作系统一个重要的模块.在理解进程概念同时,还需了解如何控制进程.对于进程控制,通常分成1.进程创建  (fork函数) 2.进程等待(wait系列) 3.进程替换(exec系列) 4 ...

  3. 实现一个简单的Tomcat

    实现一个简单的Tomcat 1. Tomcat作用 我们的web应用会运行在Tomcat中,那么显然请求必定是先到达Tomcat的,Tomcat对于请求实际上会进行如下的处理: 提供Socket服务: ...

  4. 模拟一个简单的tomcat

    目录 简单处理 每个请求一个线程 模拟tomcat 参考 简单处理 // 客户端和服务器的通信,说到底就是两个数据的传输, // 客户端发送inputStream给服务器,服务器回复 // outpu ...

  5. 自己动手模拟开发一个简单的Web服务器

    开篇:每当我们将开发好的ASP.NET网站部署到IIS服务器中,在浏览器正常浏览页面时,可曾想过Web服务器是怎么工作的,其原理是什么?“纸上得来终觉浅,绝知此事要躬行”,于是我们自己模拟一个简单的W ...

  6. 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序

    对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...

  7. jsonp 原理 并模拟实现一个简单的jsonp

    jsonp产生的背景 1.从原网站向目标网站(服务端)发送ajax请的时候,由于浏览器的安全策略(这两个网站只要域名,端口,协议 有一个不同就不允许请求访问)导致跨域,从而请求无法正常进行. 2.We ...

  8. java模拟而一个电话本操作

    哈哈.大家平时都在使用电话本.以下使用java来模拟而一个简单的电话本吧... 首先给出联系人的抽象类 package net.itaem.po; /** * * 电话人的信息 * */ public ...

  9. ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁

    作者:Grey 原文地址: ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 当多个进 ...

随机推荐

  1. MySQL innodb_table_monitor 解析

    背景:       用innodb_table_monitor来查看表内部的存储信息和索引结构是一个好的办法.再之前的MySQL 字符串主键和整型主键分析中提到了一些内容,但没有细讲,现在来好好的分析 ...

  2. 如何在一个项目中同时包含mvc建站、webapi接口

    项目做得多了..就会发现有些小项目不想建太多的项目..现在思明在这里和大家分享一下如果再一个项目中同时包含mvc建站以及实现webapi接口 1.新建项目 aps.net web 应用程序 2 新建模 ...

  3. 《JAVA程序设计与实例》记录与归纳--继承与多态

    继承与多态 概念贴士: 1. 继承,即是在已经存在的类的基础上再进行扩展,从而产生新的类.已经存在的类成为父类.超类和基类,而新产生的类成为子类或派生类. 2. Java继承是使用已存在的类的定义作为 ...

  4. [转]设置Jupyter-Notebook表格打印多个变量的值

    有一点已经众所周知.把变量名称或没有定义输出结果的语句放在cell的最后一行,无需print语句,Jupyter也会显示变量值.当使用Pandas DataFrames时这一点尤其有用,因为输出结果为 ...

  5. Quartz 代码调用Demo

    一般项目中Quartz都是直接在配置文件中配置,但是一些特殊的情况需要在代码中控制,本文为代码调用的Demo,仅供参考.更多详细的Quartz配置信息,请查看: JAVA定时任务实现的几种方式 mav ...

  6. 关于maven项install时报找不到符号的错误

    解决办法: 聚合工程: 1.eclipse中执行project -->clean,将项目清理一下: 2.选中聚和工程右键-->Run As-->Maven builed...--&g ...

  7. HDU 2079 dp解法

    选课时间(题目已修改,注意读题) Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. [国嵌攻略][100][嵌入式Linux内核制作]

    Linux内核制作步骤 1.清除原有配置 make distclean 2.配置内核 选择一个已有的配置文件简化配置 make menuconfig ARCH=arm 3.编译内核 ARCH指明处理器 ...

  9. java中的分支结构 switch case的使用

    switch(A),括号中A的取值只能是整型或者可以转换为整型的数值类型,比如byte.short.int.char.string(jdk1.7后加入)还有枚举:需要强调的是:long是不能用在swi ...

  10. FileZilla出现Failed to convert command to 8 bit charset 

    FileZilla这款FTP客户端软件,自从华哥使用以来,采用其默认的设置,一直用得很顺畅,没有出现过什么问题.但是今天碰到了一个问题.如图. 错误信息为:Failed to convert comm ...