zoukankan      html  css  js  c++  java
  • 自己模拟的一个简单的tomcat

    • 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
    " + "Content-Type: text/html
    " + "Content-Length: 23
    " + "
    " + "<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();
    	}
    
    	......................
    }




  • 相关阅读:
    python环境的安装 环境变量和系统变量
    git语句(后续补充)
    pycharm的安装配置及思维导图
    python基础知识 01
    C#基础系列——异步编程初探:async和await
    Type.MakeGenericType 方法 (Type[]) 泛型反射
    ZeroFormatter
    intelliJ IDEA相关
    truesky天气系统
    tressfx hair
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5233078.html
Copyright © 2011-2022 走看看