本文是学习《Tomcat深入剖析》后,对书中内容的总结,主要用于自己学习记录,纯手打。。。
Servlet定义:Servlet是运行在服务的一个小程序(由若干个类组成,并完成指定的功能)。
Servlet的调用过程:浏览器发送请求到服务器端,服务器端(如:Tomcat)接收请求后按照Http协议提取出URI,然后再根据URI中Servlet的名字,利用Java反射机制加载Servlet,最后执行相应的业务逻辑。
所有的Servlet必须实现javax.servlet.Servlet这个接口(为什么必须实现这个接口呢?百度搜索 实现接口的好处)
下面将建立一个非常简单的Servlet容器,它不会像Tomcat那样完成所有功能,仅仅有以下功能:
1、等待HTTP请求;
2、创建一个servletRequest对象(解析HTTP请求)和一个servletResponse对象(发送数据到浏览器);
3、判断请求的是一个静态资源还是一个Servlet类,并执行对应的方法。
本程序一共有6个类:MyHttpServer(启动程序)、Request(解析请求)、Response(发送数据)、StaticResourceProcessor(处理静态请求)、ServletProcessor(处理Servlet请求)、Constans(常量存放)
以下是容器的UML类图:
================分割线================
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.InetAddress;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.net.UnknownHostException;
- /**
- *
- * MyHttpServer类主要作用:
- * 设置服务器根路径WEB_ROOT
- * new一个SeverSocket实例监听对应的端口当有响应到达时,调用accept方法返回一个Socket实例
- * 获取Socket实例的输入输出流,使用自定义的Request对输入流按照Http协议进行解析,Response则按照Http协议进行数据的发送
- */
- public class MyHttpServer {
- /**
- * 定义服务关闭指令
- */
- private static final String SHUTDOWN_COMMAND="/SHUTDOWN";
- /**
- * 定义服务器关闭状态,例如:shutdown=false表示服务正在运行
- */
- private boolean shutdown=false;
- public static void main(String[] args){
- MyHttpServer myMailServer=new MyHttpServer();
- myMailServer.await();
- }
- public void await(){
- ServerSocket serverSocket=null;
- /**
- * 指定服务器默认监听端口
- */
- int port = 8888;
- /**
- * 指定服务器请求队列最大长度
- */
- int backlog=1;
- /**
- * 指定serverSocket监听的主机
- */
- InetAddress address= null;
- try {
- address= InetAddress.getByName("127.0.0.1");
- serverSocket=new ServerSocket(port, backlog, address);
- }catch(UnknownHostException e){
- e.printStackTrace();
- System.exit(1);
- }catch (IOException e) {
- e.printStackTrace();
- System.exit(1);
- }
- System.out.println("服务器已成功启动");
- while(!shutdown){
- Socket socket=null;
- InputStream inputStream=null;
- OutputStream outputStream=null;
- try {
- socket=serverSocket.accept();
- System.out.println("服务器收到一个请求");
- inputStream=socket.getInputStream();
- outputStream=socket.getOutputStream();
- /**
- * 构建一个Request类,用以解析Http请求的原始数据
- */
- Request request =new Request(inputStream);
- /**
- * 解析Http请求
- */
- request.parse();
- /**
- * 构建一个Response类,用以返回请求
- */
- Response response=new Response(outputStream);
- /**
- * 设置response,为返回请求做准备
- */
- response.setRequest(request);
- /**
- * 判断Http请求静态资源还是servlet
- * 例如浏览器中输入 127.0.0.1:8888/servlet/MyFirstServlet ,
- * 其中/servlet/表示请求的是一个servlet,servlet名称为MyFirstServlet
- */
- if(request.getUri().startsWith("/servlet")){
- /**
- * 如果Http请求servlet,调用ServletProcessor进行处理
- */
- ServletProcessor servletProcessor=new ServletProcessor();
- servletProcessor.process(request,response);
- }else{
- /**
- * 如果Http请求静态资源,调用StaticResourceProcessor进行处理
- */
- StaticResourceProcessor staticResourceProcessor=new StaticResourceProcessor();
- staticResourceProcessor.process(request,response);
- }
- socket.close();
- shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- System.out.println("服务器关闭");
- }
- }
- 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.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 inputStream;
- private String uri;
- /**
- * 创建Request时传入一个InputStream对象
- */
- public Request(InputStream inputStream) {
- this.inputStream=inputStream;
- }
- /**
- * parse()方法作用是将浏览器发送到服务器到数据转换为一个字符串
- */
- public void parse() {
- /**
- * 定义一个StringBuffer对象,用以存储InputStream中传入的数据
- */
- StringBuffer request=new StringBuffer(2048);
- byte[] bytes=new byte[2048];
- int i=-1;
- try {
- /**
- * 读取inputStream中的数据,并把读取的存入一个byte数组中
- */
- i=this.inputStream.read(bytes);
- } catch (IOException e) {
- e.printStackTrace();
- }
- for(int j=0;j<i;j++){
- /**
- * 将byte数组中的数据放入StringBuffer中
- */
- request.append((char)bytes[j]);
- }
- System.out.println(request.toString());
- this.uri=parseUri(request.toString());
- }
- /**
- * parseUri()的作用是提取字符串request中的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 String getUri() {
- return this.uri;
- }
- @Override
- public AsyncContext getAsyncContext() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Object getAttribute(String name) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Enumeration<String> getAttributeNames() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getCharacterEncoding() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int getContentLength() {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public String getContentType() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public DispatcherType getDispatcherType() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public ServletInputStream getInputStream() throws IOException {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getLocalAddr() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getLocalName() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int getLocalPort() {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public Locale getLocale() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Enumeration<Locale> getLocales() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getParameter(String name) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Map<String, String[]> getParameterMap() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Enumeration<String> getParameterNames() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String[] getParameterValues(String name) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getProtocol() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public BufferedReader getReader() throws IOException {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getRealPath(String path) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getRemoteAddr() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getRemoteHost() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int getRemotePort() {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public RequestDispatcher getRequestDispatcher(String path) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getScheme() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getServerName() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int getServerPort() {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public ServletContext getServletContext() {
- // 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 boolean isSecure() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void removeAttribute(String name) {
- // TODO Auto-generated method stub
- }
- @Override
- public void setAttribute(String name, Object o) {
- // TODO Auto-generated method stub
- }
- @Override
- public void setCharacterEncoding(String env)
- throws UnsupportedEncodingException {
- // TODO Auto-generated method stub
- }
- @Override
- public AsyncContext startAsync() throws IllegalStateException {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public AsyncContext startAsync(ServletRequest servletRequest,
- ServletResponse servletResponse) throws IllegalStateException {
- // TODO Auto-generated method stub
- return null;
- }
- }
- 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;
- private OutputStream outputStream;
- /**
- * 定义一个request对象,获取request中的uri
- */
- private Request request;
- private PrintWriter printWriter;
- public PrintWriter getPrintWriter() {
- return printWriter;
- }
- public void setPrintWriter(PrintWriter printWriter) {
- this.printWriter = printWriter;
- }
- public Response(OutputStream outputStream) {
- this.outputStream=outputStream;
- }
- public void setRequest(Request request) {
- this.request=request;
- }
- public void sendStaticResource() throws IOException{
- byte[] bytes=new byte[BUFFER_SIZE];
- FileInputStream fis=null;
- try {
- /**
- * 加载请求资源文件
- */
- File file=null;
- file=new File(Constants.WEB_ROOT,request.getUri());
- System.out.println("请求资源绝对路径"+file.getAbsolutePath());
- if(file.exists()){
- fis=new FileInputStream(file);
- /**
- * 读取file,每次读取长度为BUFFER_SIZE
- */
- int ch=fis.read(bytes, 0, BUFFER_SIZE);
- while(ch!=-1){
- this.outputStream.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"+
- "Context-Type:text/html\r\n"+
- "Context-Length:23\r\n"+
- "\r\n"+
- "<h1>File Not Found</h1>";
- this.outputStream.write(errorMessage.getBytes());
- e.printStackTrace();
- }finally{
- if(fis!=null){
- fis.close();
- }
- }
- }
- @Override
- public void flushBuffer() throws IOException {
- }
- @Override
- public int getBufferSize() {
- return 0;
- }
- @Override
- public String getCharacterEncoding() {
- return null;
- }
- @Override
- public String getContentType() {
- return null;
- }
- @Override
- public Locale getLocale() {
- return null;
- }
- @Override
- public ServletOutputStream getOutputStream() throws IOException {
- return null;
- }
- @Override
- public PrintWriter getWriter() throws IOException {
- this.printWriter = new PrintWriter(this.outputStream,true);
- return printWriter;
- }
- @Override
- public boolean isCommitted() {
- return false;
- }
- @Override
- public void reset() {
- }
- @Override
- public void resetBuffer() {
- }
- @Override
- public void setBufferSize(int arg0) {
- }
- @Override
- public void setCharacterEncoding(String arg0) {
- }
- @Override
- public void setContentLength(int arg0) {
- }
- @Override
- public void setContentType(String arg0) {
- }
- @Override
- public void setLocale(Locale arg0) {
- }
- }
- import java.io.IOException;
- public class StaticResourceProcessor {
- public void process(Request request, Response response) {
- try {
- response.sendStaticResource();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- import java.io.File;
- import java.io.IOException;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.net.URLStreamHandler;
- import javax.servlet.Servlet;
- import javax.servlet.ServletException;
- public class ServletProcessor {
- public void process(Request request, Response response) {
- /**
- * 获取传入request的uri
- */
- String uri=request.getUri();
- /**
- * 截取uri中请求的servletName
- */
- String servletName=uri.substring(uri.lastIndexOf("/")+1);
- /**
- * 定义一个URLClassLoader,用以加载指定路径下的类。
- * ClassLoader只能加载classpath下的类,URLClassLoader可以加载任意路径下的类
- */
- URLClassLoader urlClassLoader=null;
- /**
- * 定义一个URL类数组(只存放一个数据),类 URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或
- * 目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。
- */
- URL[] urls=new URL[1];
- /**
- * 定义一个URLStreamHandler
- */
- URLStreamHandler urlStreamHandler=null;
- /**
- * 指定服务器WebRoot目录的路径
- */
- File classpath=new File(Constants.WEB_ROOT);
- try {
- String repository=(new URL("file",null,classpath.getCanonicalPath()+File.separator)).toString();
- System.out.println("请求资源目录:"+repository);
- urls[0]=new URL(null,repository,urlStreamHandler);
- urlClassLoader = new URLClassLoader(urls);
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- Class myClass = null;
- try {
- /**
- * 加载Http请求的servlet
- */
- myClass=urlClassLoader.loadClass(servletName);
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- Servlet servlet=null;
- try {
- /**
- * servlet实例化
- */
- servlet=(Servlet) myClass.newInstance();
- /**
- * 调用servlet的service()方法
- */
- servlet.service(request, response);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (ServletException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- import java.io.File;
- public class Constants {
- /**
- * 设置服务器根目录,里面存放各种资源
- * 注意:“webroot”后面如果有分隔符则表示“webroot”是一个目录,下面还有子文件,如果后面没有分隔符则表示“webroot”是一个具体的文件
- */
- public static final String WEB_ROOT=System.getProperty("user.dir")+File.separator+"webroot"+File.separator;
- }
- 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 MyFirstServlet implements Servlet {
- @Override
- public void destroy() {
- // TODO Auto-generated method stub
- }
- @Override
- public ServletConfig getServletConfig() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public String getServletInfo() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public void init(ServletConfig config) throws ServletException {
- // TODO Auto-generated method stub
- }
- @Override
- public void service(ServletRequest req, ServletResponse res)
- throws ServletException, IOException {
- PrintWriter printWriter=res.getWriter();
- System.out.println("servlet开始执行");
- printWriter.println("Hello,Servlet");
- }
- }
在浏览器中输入http://127.0.0.1:8888/servlet/MyFirstServlet,结果如下:
注意:编译后的MyFirstServlet.class文件必须放在WebRoot目录下。