tomcate 步步深入

开篇讲述简单的请求及响应的过程
1.建立一个ServerSocket
2.从socket中获取InputStream
3.解析inputStream中请求头中的uri
4.从socket中获取OutputStream
5.从web_root下获取uri中指定文件路径并将静态文件Html输出到页面
 
HttpServer main方法
try {
			//新建server,监听本地8080端口
			 serverSocket=new ServerSocket(8080, 1, InetAddress.getByName("127.0.0.1"));
			 System.out.println("....server start...");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		while(!shutdown){
		try {
			Socket socket=serverSocket.accept();
			in=socket.getInputStream();
			out=socket.getOutputStream();
			Request request=new Request(in);
			//解析请求http请求
			request.parse();
			
			Response response=new Response(out);
			response.setRequest(request);
			response.sendStaticResource();
			
			socket.close();
			
			shutdown=request.getUri().equals(SHUTDOWN_COMMAND);
			
		}
     Request.java
	public void parse(){
		StringBuffer request=new StringBuffer(2048);
		int i;
		byte[] buffer=new byte[2048];
		try {
			i=input.read(buffer);
		} catch (Exception e) {
			e.printStackTrace();
			i=-1;
		}
		for (int j = 0; j < i; j++) {
			request.append((char)buffer[j]);
		}
		System.out.println(request.toString());
		uri=parseUri(request.toString());
	}

	public String getUri(){
		return uri;
	}
	/**
	 * http请求第一行格式  <p/>
	 * 请求方法  uri 协议
	 * @param requestString
	 * @return
	 */
	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;
	}
    Response.java   
public void sendStaticResource(){
		byte[] bytes=new byte[BUFFER_SIZE];
		FileInputStream fis=null;
		try {
			File file=new File(HttpServer.WEB_ROOT,request.getUri());
			if(file.exists()){
				fis=new FileInputStream(file);
				int ch=fis.read(bytes, 0, BUFFER_SIZE);
				while(ch!=-1){
					out.write(bytes,0,ch);
					ch=fis.read(bytes, 0, BUFFER_SIZE);
				}
			
			}else{
				String errorMsg="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>";
				out.write(errorMsg.getBytes());
			}
		} catch (Exception e) {
			System.out.println(e.toString());
		}
                  第二部分 在前章处理静态资源的基础上,加入处理servlet请求的方法。成为简单的servlet容器,而不仅仅是一个web服务器。
需要加入的内容:
 1.request解析请求头uri后判断检查request是针对servlet还是静态资源
if(request.getUri().startsWith("/servlet/")){
					ServletProcessor1 processor=new ServletProcessor1();
					processor.process(request,response);
   2.实例化ServletProcessor类传入response,request。初始化一个类加载器并加载相关的serlvet类。
URL urls[]=new URL[1];
			//根据不用协议流建立不同链接 ftp/http/
			URLStreamHandler streamHandler=null;
			File classPath=new File(Constants.WEB_ROOT);
			
			String repository=(new URL("file",null,classPath.getCanonicalPath()+File.separator)).toString();
			//指定第三个参数编译器才知道调用哪个构造函数,不然报错
			urls[0]=new URL(null,repository,streamHandler);
			//如果ULR以/结尾则是目录,否则是jar,这里查找工作目录下的webroot
			System.out.println(repository);
			loader=new URLClassLoader(urls);

.....

	Class myClass=null;
		try {
			myClass=loader.loadClass(servletName);
		} catch (Exception e) {
			System.out.println(e.toString());
		}
		
		Servlet servlet=null;
		
		try {
			servlet=(Servlet)myClass.newInstance();
			servlet.service((ServletRequest)request, (ServletResponse)response);
		} catch (Exception e) {
			e.printStackTrace();
		}
 
 3.PrimitiveServlet类收到请求后调用service方法并打印输出结果。
public class PrimitiveServlet implements Servlet {

......

@Override
	public void service(ServletRequest arg0, ServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("from service");
		PrintWriter out=response.getWriter();
		out.println("Hello .ROses are red");
		out.println("violets are blue");
		out.flush();
	}



}
   4. Request和Response类分别需要实现ServletRequest,ServletResponse接口。这里我们先把需要实现的方法均留空不处理。需要处理的:
 
public class Response implements ServletResponse {
...
public PrintWriter getWriter() throws IOException {
		// TODO Auto-generated method stub
		return new PrintWriter(out); 
	}
...
}
  5.加入门面模式Facade来区别tomcat系统开发人员和用户对request,reponse方法的使用提高安全性,拿出部分方法对使用者可见。大家可以看看很多源码都采用了Facade模式,比如代码生成器:rapid_framework,spring -quartz等。思考下HttpProcessor在每次请求时候都需要新建一个Processor来处理请求,可以利用对象池进行优化。每个Processor可以使用新的线程来处理,防止线程阻塞等。后面将说明这些问题。
  
/**
 * 定义外观类,所有方法在servlet中可见的,<p/>
 * 只是Request中的部分方法,其它方法不可访问,这样方法才更安全
 * @author greenn [email protected]
 * CopyRight Huawei   2013-11-20
 *
 */
public class HttpRequestFacade implements ServletRequest{
	
	private HttpRequest request;

	public HttpRequestFacade(HttpRequest request) {
		// TODO Auto-generated constructor stub
		this.request=request;
	}

	@Override
	public AsyncContext getAsyncContext() {
		// TODO Auto-generated method stub
		return request.getAsyncContext();
	}
....
 
 
	try {
			servlet=(Servlet)myClass.newInstance();
			servlet.service(new HttpRequestFacade(request), new HttpResponseFacade(response));
		} catch (Exception e) {
			e.printStackTrace();
		}
  第三部分 模拟Tomcat默认连接器,罗列一些优化性能的思路方法。 1.HttpConnector及HttpProcessor类均实现Runable接口来运行在自己的线程中无需等待某个HttpProcessor实例完成解析。
2.容器类均实现了LifeCycle接口。当创建一个HttpConnector实例后,就会调用其initialize()方法和start()方法。在组件的整个生命周期内,这两个方法均被调用一次。
3.HttpConnector维护HttpProcessor池。  

你可能感兴趣的:(tomcat)