HttpServlet分析

个人觉得要把javaWeb那一套搞清楚,首先得要把servlet的那一套东西搞清楚吧,本来是打算要看spring的DispatcherServlet,但是发现自己这方面的基础还比较的薄弱,那么就从servlet这块补起来吧...

我们一般情况下编写servlet都会继承HttpServlet这个类型,然后重载它的doGet和doPost两个方法..

先来看看它的继承体系:



整个继承体系还是比较的简单的,那么我们就从最顶层的Servlet接口的定义开始吧:

public interface Servlet {
	//初始化的时候被servlet容器调用,只有init之后,servlet才能被用于处理请求
    public void init(ServletConfig config) throws ServletException;
    
    //获取servlet的config对象,里面包括了servlet的启动参数等
    public ServletConfig getServletConfig();
    
    //当有http请求进来之后,将会调用这个方法来处理
    public void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
	
    //返回这个servlet的基本信息,例如版本,作者等
    public String getServletInfo();
    
    //servlet的销毁,只有所有的线程的service方法都执行了之后这个方法才能调用
    public void destroy();
}

本身接口的定义比较的简单,其中有两个比较重要的方法:

(1)init方法:这个是servlet的初始化方法,在这个servlet可以用之前,servlet容器将会调用这个方法,并传入config对象,只有init之后了,这个servlet才能被用于处理http请求。

(2)service方法:这个方法就是用于处理http请求的,当一个http请求进来之后,servlet容器会找到相应的servlet然后调用service方法来处理。


接下来来看看ServletConfig这个接口的定义:

 //servlet在初始化的时候,由servlet容器传递给servlet
public interface ServletConfig {
	
	//返回servlet的名字
    public String getServletName();

    //返回当前servlet的执行上下文
    public ServletContext getServletContext();
    
    //获取相应的初始化参数
    public String getInitParameter(String name);

    //获取初始化参数名
    public Enumeration getInitParameterNames();

}

前面已经提到过,servlet容器在初始化servlet的时候会传入一个config对象,它有一个方法getServletContext,用于获取当前servlet的context,每一个webApplication都有一个自己的context。

那么接下来来看看GenericServlet的定义吧:

public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable
{

    private transient ServletConfig config;  //保证这个属性在当前对象的序列化的时候不会被保存
    
    public GenericServlet() { }
    
    public void destroy() {
    }

    //获取一个初始化参数的值
    public String getInitParameter(String name) {
    	return getServletConfig().getInitParameter(name);
    }

    //返回所有初始化参数的名字,其实就相当于对congfig做了一层代理
    public Enumeration getInitParameterNames() {
    	return getServletConfig().getInitParameterNames();
    }   
    
    public ServletConfig getServletConfig() {
    	return config;
    }
    
    //获取当前servlet的context
    public ServletContext getServletContext() {
    	return getServletConfig().getServletContext();
    }
    //当前servlet的基本信息,例如作者啥的
    public String getServletInfo() {
    	return "";
    }

    //servlet容器调用这个方法来初始化servlet,servlet容器会传进来servlet的config对象
    public void init(ServletConfig config) throws ServletException {
		this.config = config;
		this.init();
    }

    //以后的子类覆盖
    public void init() throws ServletException {
    }
    
    //写日志 
    public void log(String msg) {
    	getServletContext().log(getServletName() + ": "+ msg);
    }
   
   
    public void log(String message, Throwable t) {
    	getServletContext().log(getServletName() + ": " + message, t);
    }
   
    //用于处理http请求
    public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    
    //获取当前servlet的名字
    public String getServletName() {
        return config.getServletName();
    }
}

它是一个抽象类,这里它也实现了ServletConfig接口,我们在前面已经知道,servlet在初始化的时候会由servlet容器传入这个config对象,这里实现了ServletConfig接口其实无非是对拥有的config对象做了一层代理。。。

其实它实现的方法并不多,而且都是一些基本的方法,很多方法的实现其实都是在HttpServlet中,这里我们就来看看它最重要的一个方法就可以了,service方法:

    //根据不同的http请求调用不同的方法来处理
    protected void service(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException
    {
		String method = req.getMethod();
		//如果http请求是get类型的
		if (method.equals(METHOD_GET)) {
		    long lastModified = getLastModified(req);
		    if (lastModified == -1) {
			// servlet doesn't support if-modified-since, no reason
			// to go through further expensive logic
		    	doGet(req, resp);  //处理get请求
		    } else {
				long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
				if (ifModifiedSince < (lastModified / 1000 * 1000)) {
				    // If the servlet mod time is later, call doGet()
		                    // Round down to the nearest second for a proper compare
		                    // A ifModifiedSince of -1 will always be less
				    maybeSetLastModified(resp, lastModified);
				    doGet(req, resp);
				} else {
				    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
				}
		    }
	
		} else if (method.equals(METHOD_HEAD)) {
		    long lastModified = getLastModified(req);
		    maybeSetLastModified(resp, lastModified);
		    doHead(req, resp);
	
		} else if (method.equals(METHOD_POST)) {
		    doPost(req, resp);
		    
		} else if (method.equals(METHOD_PUT)) {
		    doPut(req, resp);	
		    
		} else if (method.equals(METHOD_DELETE)) {
		    doDelete(req, resp);
		    
		} else if (method.equals(METHOD_OPTIONS)) {
		    doOptions(req,resp);
		    
		} else if (method.equals(METHOD_TRACE)) {
		    doTrace(req,resp);
		    
		} else {
		    //
		    // Note that this means NO servlet supports whatever
		    // method was requested, anywhere on this server.
		    //
	
		    String errMsg = lStrings.getString("http.method_not_implemented");
		    Object[] errArgs = new Object[1];
		    errArgs[0] = method;
		    errMsg = MessageFormat.format(errMsg, errArgs);
		    
		    resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
		}
    }

这里就可以看出,根据不同的http请求,例如get和post,调用相应的方法来处理它,因此我们自己在写servlet的时候只要重载这两个方法就可以了。。。另外因为servlet都是在线程池中执行的,所以需要考虑servlet的并发问题。。。。


那么到这里整个servlet的大体的设计就已经有了一定的了解,用户只需要编写servlet,而后其余的事情都是servlet容器来做的了。。。它会来初始化servlet,为servlet传入config对象,还有为webApplication分配context,以及当有http请求进来的时候,调用servlet的service方法来处理,同时要传入request和response对象。。

由此可见,servlet容器其实做了最多的请示。。。

这里还有一个东西补充一下,那就是ServletContext,每一个webApplication都有一个context,是由servlet容器分配的,它可以用于servlet与servlet容器之间进行交互。。。

来看看它的定义吧:

//定义了一些方法用于servlet与其容器进行交流,每一个webapplication都有一个
public interface ServletContext {

	//获取一个url的context,可以用于获取别的application的context,为了安全一般情况下servlet容器会返回null 
    public ServletContext getContext(String uripath);

    public String getContextPath();

    //返回servlet的api版本
    public int getMajorVersion();
    
    //版本信息
    public int getMinorVersion();
    
    //返回一个文件的mime类型
    public String getMimeType(String file);

    //返回当前path下面的所有资源的路径  getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}
    public Set getResourcePaths(String path);
    

    //返回一个资源的外面访问的url
    public URL getResource(String path) throws MalformedURLException;


    //返回一个资源的访问stream
    public InputStream getResourceAsStream(String path);

    //返回一个path的Dispatcher对象,可以用于路由http请求
    public RequestDispatcher getRequestDispatcher(String path);

    //通过servlet的名字,获取它的Dispatcher
    public RequestDispatcher getNamedDispatcher(String name);

    public Servlet getServlet(String name) throws ServletException;
    
    public Enumeration getServlets();
    
    public Enumeration getServletNames();
    
      //写日志
    public void log(String msg);
    
    public void log(Exception exception, String msg);
    
    
    public void log(String message, Throwable throwable);
    
    //返回一个path的事件path,例如"/index.html" -->"http://host/contextPath/index.html
    public String getRealPath(String path);
    
    //返回servlet容器的版本信息
    public String getServerInfo();

//返回一个初始化参数的值
    public String getInitParameter(String name);

//返回初始化参数的名字
    public Enumeration getInitParameterNames();

//获取属性  
    public Object getAttribute(String name);
    
    //返回所有的属性名
    public Enumeration getAttributeNames();

//设置属性
    public void setAttribute(String name, Object object);
    
//删除属性
    public void removeAttribute(String name);
    
    //context的名字
    public String getServletContextName();
}

其实这里可以看到大多数方法都是与资源的访问有关的。。。


看到这里,其实发现如果要对整个javaWeb有比较系统的认识的话,其实还需要对servlet容器的运行有一定的了解,那以后就拿jetty服务器作为入口来分析吧。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值