• 《深入剖析Tomcat》阅读(二)


       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
    " + "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)
    	{
    	}
    
    	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());
        }
    
      }
    }
    

      

  • 相关阅读:
    unityshader(属性)
    unity_实用小技巧(相机跟随两个主角移动)
    unity_实用小技巧(空指针错误)
    unity_实用小技巧(避免游戏对象被销毁时声音消失)
    php把网络图片转Base64编码。(php将图片链接直接转化为base64编码)
    TP5.0 where数组高级查询
    使用Guzzle执行HTTP请求
    JWT实战:使用axios+PHP实现登录认证
    有关JWT(Json Web Token)的那些事
    thinkphp5一键清除缓存
  • 原文地址:https://www.cnblogs.com/wuxinliulei/p/4899632.html
Copyright © 2020-2023  润新知