`
异步获取爱
  • 浏览: 79961 次
  • 性别: Icon_minigender_1
  • 来自: 大男子主义世界
社区版块
存档分类
最新评论

看了servlet源码后一点总结

阅读更多
       这几天上班时间( )没什么别的大事,就自己看了一下servlet的api,已经把源码放进项目里,边看api边看源码,自己写一点心得体会,也是对这个的一些小总结,希望让自己有点提升。废话不多说开始写。
       servlet属于服务器端的程序,也就是说它的职责是充当客户请求和服务器响应的中间层。servlet的生命周期一般是首先装载servlet,也就是启动服务的时候,服务器端调用servlet的init()方法进行初始。当一个客户端请求到达服务器,服务器首先先生成一个请求对象(ServletRequest)和一个响应对象(ServletResponse),然后服务激活servlet的service()方法,将刚刚的请求对象和响应对象进行传递,通过请求对象,对对象的信息,请求的资源进行封装,再通过服务端将响应对象传递回客户端。一般servlet只需要创建一次就可以(也就是只调用一次init()方法),当不再需要servlet的时候就调用destory()方法销毁servlet对象。servlet里的接口Servlet正是各种Servlet的接口,也就是说,所有的Servlet都必须实现这个接口。
public abstract interface Servlet {

	public abstract void init(ServletConfig paramServletConfig)
			throws javax.servlet.ServletException;

	public abstract ServletConfig getServletConfig();

	public abstract void service(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse)
			throws javax.servlet.ServletException, IOException;

	public abstract String getServletInfo();

	public abstract void destroy();
}


比如GenericServlet,就是实现了Servlet接口,并且GenericServlet是属于无协议的,通用的Servlet,这里我们来看下GenericServlet的代码:
public abstract class GenericServlet implements Servlet, ServletConfig,
		Serializable {
	private transient ServletConfig config;

	public String getInitParameter(String name) {
		return getServletConfig().getInitParameter(name);
	}

	public Enumeration<String> getInitParameterNames() {
		return getServletConfig().getInitParameterNames();
	}

	public ServletConfig getServletConfig() {
		return this.config;
	}

	public ServletContext getServletContext() {
		return getServletConfig().getServletContext();
	}

	public void init(ServletConfig config)
			throws javax.servlet.ServletException {
		this.config = config;
		init();
	}

	public abstract void service(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse)
			throws javax.servlet.ServletException, IOException;

	public String getServletName() {
		return this.config.getServletName();
	}
}

      当然,这里的GenericServlet 并不是完整的,因为一些无用的或者是抽象的方法,我就没有放进去,具体想要了解全部的可以自行下载其源码进行查看。GenericServlet之所以是无协议的,是因为service()方法依旧是需要继承的类进行实现的,整个类里有ServletConfig对象,该对象所实现的接口就是ServletConfig接口,代码为:
public abstract interface ServletConfig
{
  public abstract String getServletName();

  public abstract ServletContext getServletContext();

  public abstract String getInitParameter(String paramString);

  public abstract Enumeration<String> getInitParameterNames();
}

      也就是说,servletConfig对象里存储了servlet的一些配置信息,包括ServletContext等,这样就方便实现servlet之间消息的传递。而实现servlet容器之间消息传递的方法的,就是其中的ServletContext,部分源码如下:
public abstract interface ServletContext {

	public abstract ServletContext getContext(String paramString);

	public abstract String getContextPath();

	public abstract String getMimeType(String paramString);

	public abstract Set<String> getResourcePaths(String paramString);

	public abstract URL getResource(String paramString)
			throws MalformedURLException;

	public abstract InputStream getResourceAsStream(String paramString);

	public abstract RequestDispatcher getRequestDispatcher(String paramString);

	public abstract RequestDispatcher getNamedDispatcher(String paramString);

	public abstract void log(String paramString);

	public abstract void addListener(String paramString);

	public abstract <T extends EventListener> T createListener(
			Class<T> paramClass) throws javax.servlet.ServletException;

	public abstract ClassLoader getClassLoader();

	public abstract JspConfigDescriptor getJspConfigDescriptor();
}

      这些代码里有获得文件MIME类型的,还有分发请求的,写日志的等等。每个虚拟机都会为web项目分配context(web项目是一批servlet集合, 它的内容安装在服务器上特定URL命名空间的自己下,例如/catalog,抑或通过 .war文件安装在服务器上)。这里有一个方法getRequestDispatcher()返回了RequestDispatcher,我们来看下RequestDispatcher接口的内容
public abstract interface RequestDispatcher
{
      /**省略很多字符常量 **/
      /**
        * 将Servlet中的一个请求转交给服务器上的另一个资源(例如 sevlet、JSP文件或HTML文件), 方法允许Servlet在生成响应之前对请求和被转发到的那个资源进行预处理.
        * @param paramServletRequest
        * @param paramServletResponse
        * @throws javax.servlet.ServletException
        * @throws IOException
        */
      public abstract void forward(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
       throws javax.servlet.ServletException, IOException;

     /**
        * 将资源(例如 servlet、JSP页面或HTML文件)内容包含到响应流中. 实质上方法默认启用了服务端按队列包含文件. 
        * @param paramServletRequest
        * @param paramServletResponse
        * @throws javax.servlet.ServletException
        * @throws IOException
        */
      public abstract void include(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
       throws javax.servlet.ServletException, IOException;
}

       其实一看就很清楚,这个RequestDispatcher就是定义一个可以接受客户端请求并且能转发到服务器上的任何一种资源的对象,.Servlet容器创建的那个RequestDispatcher对象已经事先封装好了服务器端本地(或通过参数名提供给服务器的)资源。也就是先通过forward()方法分发请求,再通过include()方法将返回的资源包含进响应(response)里。

       下面我们来看下HttpServlet这个类,这是一个通过扩展子类创建兼容Web站点的HTTP Servlet的抽象类. HttpServlet子类必须至少重写接口中的一个方法(doPost,doGet,doPut,doDelete)。

public abstract class HttpServlet extends GenericServlet {
       /**
	 * 继承HttpServlet的所有子类,必须重写一个方法,通常是以下四个之一
	 * @param req
	 * @param resp
	 * @throws ServletException
	 * @throws IOException
	 */
       protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String protocol = req.getProtocol();
		String msg = lStrings.getString("http.method_get_not_supported");
		if (protocol.endsWith("1.1"))
			resp.sendError(405, msg);
		else
			resp.sendError(400, msg);
	}
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {}
	protected void doPut(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {}
	protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {}
}

           再然后是两个重载的service方法,但是一般不需要重写,但是我个人觉得这个service()方法在整个HttpServlet中扮演了重要的角色。
      public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		HttpServletRequest request;
		HttpServletResponse response;
		try {
			request = (HttpServletRequest) req;
			response = (HttpServletResponse) res;
		} catch (ClassCastException e) {
			throw new ServletException("non-HTTP request or response");
		}
		service(request, response);
	}

       protected void service(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		long lastModified;
		String method = req.getMethod();

		if (method.equals("GET")) {
			lastModified = getLastModified(req);
			if (lastModified == -1L) {
				doGet(req, resp);
			} else {
				long ifModifiedSince = req.getDateHeader("If-Modified-Since");
				if (ifModifiedSince < lastModified / 1000L * 1000L) {
					maybeSetLastModified(resp, lastModified);
					doGet(req, resp);
				} else {
					resp.setStatus(304);
				}
			}
		} else if (method.equals("HEAD")) {
			lastModified = getLastModified(req);
			maybeSetLastModified(resp, lastModified);
			doHead(req, resp);
		} else if (method.equals("POST")) {
			doPost(req, resp);
		} else if (method.equals("PUT")) {
			doPut(req, resp);
		} else if (method.equals("DELETE")) {
			doDelete(req, resp);
		} else if (method.equals("OPTIONS")) {
			doOptions(req, resp);
		} else if (method.equals("TRACE")) {
			doTrace(req, resp);
		} else {
			String errMsg = lStrings.getString("http.method_not_implemented");
			Object[] errArgs = new Object[1];
			errArgs[0] = method;
			errMsg = MessageFormat.format(errMsg, errArgs);

			resp.sendError(501, errMsg);
		}
	}

      第一个service()方法很好理解,是将客户端的请求,组装成http的形式,然后交给第二个service()方法,而第2个service()方法,我们大致可以理解下整个代码的流程,就是判断是否是http的请求,然后根据判断请求的方法,分发给不同的doXXX方法,然后进行处理,也就是我们之前提到的 doPost,doGet,doPut,doDelete等方法。然后的doXXX方法,其实就是我们常说的mvc中Model层所做的业务代码。
       再来看一下service()方法中传递的参数,ServletRequest和ServletResponse。首先来看ServletRequest:
public abstract interface ServletRequest{
      public abstract Object getAttribute(String paramString);
      public abstract Enumeration<String> getAttributeNames();
      public abstract String getCharacterEncoding();
      public abstract void setCharacterEncoding(String paramString)
            throws UnsupportedEncodingException;
      public abstract int getContentLength();
      public abstract String getContentType();
      public abstract ServletInputStream getInputStream()
           throws IOException;
      public abstract String getProtocol();
      public abstract String getScheme();
      public abstract String getServerName();
      public abstract int getServerPort();
      public abstract BufferedReader getReader()
            throws IOException;
      public abstract String getRemoteAddr();
      public abstract String getRemoteHost();
      .......

      很显然,ServletRequest只不过是各种请求的一个接口,也就是说,所有的请求都会有这些方法,那么我们来看下这些方法名的意思,都是获得请求的各种参数,比如编码,协议,服务名,端口,请求IP和一些输入流对象(写请求的信息)等等。再看看ServletResponse:
public abstract interface ServletResponse
{
    public abstract String getCharacterEncoding();

    public abstract String getContentType();

    public abstract ServletOutputStream getOutputStream()
        throws IOException;

    public abstract PrintWriter getWriter()
        throws IOException;

    public abstract void setCharacterEncoding(String paramString);

    public abstract void setContentLength(int paramInt);

    public abstract void setContentType(String paramString);

    public abstract void setBufferSize(int paramInt);

    public abstract int getBufferSize();

    public abstract void flushBuffer()
        throws IOException;

    public abstract void resetBuffer();

    public abstract boolean isCommitted();

    public abstract void reset();

    public abstract void setLocale(Locale paramLocale);

    public abstract Locale getLocale();
}

      ServletResponse里所包含的,也就是一些响应的信息,包括是否重置,还有输出流的一些对象(和相应的数据),因为一般的响应都包含资源或者是html页面信息还有编码等。

      但是,ServletRequest和ServletResponse如果直接暴露在代码中,也就是会被服务器和客户端看到,这样是不安全,所以,就出现了相应的Wapper类,也就是我们常说的包装器,将ServletRequest和ServletResponse放进ServletRequestWrapper和ServletResponseWrapper就安全了,既获得了信息,也保护了信息的安全。这里就不直接列举源码了,因为Wapper里所有的方法返回的全部都是request和response的相应方法的结果。
      这里,源码包里还包含很多的Listener和Event,这些都是java里的事件机制,就是监听器一旦发现有请求过来,然后就开始做的事情。因为关于监听事件的类型,又有一大堆的东西可以说,这里主要还是自己写下Servlet,有时间可以写下监听事件的东西(不过事先需要让我再去补习下概念啊,哈哈哈哈)。而包里所有的ServletContextListener和ServletRequestListener都是监听器,都包含了相应内容(这个该不用解释是什么内容吧)初始方法和销毁方法。ServletContextAttributeListener都是上下文中的属性发生变化时的监听器,有add,remove和replace三个方法。ServletContextEvent,ServletContextAttributeEvent等几个事件对象的接口也都包装了获得context(上下文)或request来进行事件的信息传递。
    
      还有就是Filter,顾名思义就是过滤器,我们很多的项目中都会用到过滤器,而最多的就是编码过滤器和请求过滤器,都是通过实现这个接口来完成的,接口内容如下:
public abstract interface Filter {
	public abstract void init(FilterConfig paramFilterConfig)
			throws javax.servlet.ServletException;

	public abstract void doFilter(ServletRequest paramServletRequest,
			ServletResponse paramServletResponse, FilterChain paramFilterChain)
			throws IOException, javax.servlet.ServletException;

	public abstract void destroy();
}

       大多数情况下,我们只要将doFilter()方法重写,将其配置到web.xml里,那么客户端每次的请求都会经过所配置的过滤器。
      
       最后还有两个类,一个是cookie,还有一个是HttpSession,都是在javax.servlet.http包里的,也就是我们常用的,用来储存信息的东西。cookie存储了servlet发送给web浏览器的端少量信息,浏览器接收保存了Cookie信息, 以便稍后将这些信息发送给服务器.cookie值可以唯一标识一个客户端,因而通常cookie用于会话管理。而session提供了一种确定的用户跨越多个页面请求或访问网站和存储用户的相关信息。具体的区别和内容,这里就不多做解释了,相信只要有一点电经验的人对这两个对象不会陌生。
       
        文章就写到这里,也是我第一次这么详细的写自己看的东西。希望各位在阅读的同时能给予指正我写错了或者是理解错了的地方,或者有能提供更好的文章让我有质的理解的,都望勿吝字,谢谢!





      
分享到:
评论
1 楼 longfor5 2014-03-10  

相关推荐

    servlet 源码 servlet.zip压缩包

    servlet 源码 servlet.zip压缩包

    servlet源码 servlet-api-src javax.servlet.Servlet源码

    标签"Servlet源码"和"javax.servlet.Servlet源码"强调了对Servlet API源代码的学习和理解。掌握源码可以帮助开发者更好地运用Servlet,解决实际问题。而"Servlet-api-src"则表明这是一个关于Servlet API源代码的资源...

    3-6Tomcat处理源码实现与异步Servlet源码实现(1).mp4

    3-6Tomcat处理源码实现与异步Servlet源码实现(1).mp4

    java+servlet源码

    【Java + Servlet 源码解析】 在Java Web开发中,Servlet扮演着核心角色,它是一种服务器端的Java应用程序,负责处理HTTP请求并生成响应。本项目"ProjectManagementSys"是一个基于Java和Servlet的源码实例,展示了...

    servlet源码包

    通过阅读源码,可以学习到以下知识点: 1. **Servlet生命周期**:了解Servlet的初始化、服务、销毁过程,以及如何通过`init()`, `service()`, `destroy()`方法控制这些过程。 2. **请求处理流程**:观察`...

    javax.servlet源码

    在给定的"javax.servlet源码.zip"文件中,你将能够看到 javax.servlet 包内所有相关类和接口的源代码。这些源代码对于理解Servlet工作原理、学习如何编写自定义Servlet和过滤器以及调试与Servlet相关的代码非常有...

    jakarta-servletapi-4-src.zip servlet源码

    《深入理解Jakarta Servlet API 4.0源码》 Servlet技术是Java Web开发的核心,它为Web应用程序提供了服务器端的编程接口。Jakarta Servlet API 4.0是Servlet规范的最新版本,它包含了对HTTP协议处理、生命周期管理...

    servlet源码

    本篇将深入解析`servlet`源码,帮助理解其内部工作原理。 1. **Servlet接口** Servlet接口定义了Servlet的基本方法,如`init()`、`service()`、`destroy()`和`getServletInfo()`等。`init()`在Servlet实例化时被...

    Servlet源码

    - **Jasper**: JSP编译器,将JSP文件转换为Java Servlet源码。 - **Apr (Apache Portable Runtime)**: 提供高性能的网络连接和操作系统接口。 3. **Servlet容器的工作原理** - **web.xml**: 部署描述符,定义了...

    韩顺平servlet源码

    以上就是"韩顺平servlet源码"可能涉及的一些关键知识点。这个项目可能是为了帮助初学者理解Servlet如何与数据库交互以及如何实现简单的用户界面。通过实践这样的项目,开发者可以更好地掌握Servlet的精髓,并为构建...

    博客jsp+javabean+servlet源码

    博客开发是许多初学者和专业开发者接触Web应用的起点,这个源码集合涵盖了"jsp+javabean+servlet"的核心技术,是理解Web后端开发流程的重要资源。下面,我们将详细探讨这些技术及其在博客系统中的应用。 首先,JSP...

    servlet反编译源码

    反编译Servlet源码可以帮助我们深入理解其内部工作原理,这对于优化性能、调试问题或进行自定义扩展非常有帮助。下面,我们将深入探讨Servlet的基本概念、生命周期、执行流程以及如何通过反编译源码来增强我们的理解...

    serlvet 源码 servlet-src 源文件

    Servlet是Java Web应用程序的核心组件之一,它用于处理来自客户端(通常是Web浏览器)的...通过深入学习和分析`servlet-src`源码,我们可以更深入地理解Servlet的工作机制,这对于Java Web开发和问题排查具有重要意义。

    servlet源码和笔记

    在这个“servlet源码和笔记”资料中,我们将会深入探讨Servlet的工作原理、生命周期以及如何在实际项目中应用。 1. **Servlet基本概念** Servlet是一个Java类,它扩展了Java平台的功能,使得开发者可以创建动态的...

    servlet 源码

    通过分析和学习Servlet源码,可以深入了解HTTP请求的处理流程,以及如何利用Servlet API构建动态Web应用。同时,对于Java Web开发的深入理解和优化具有重要意义。在实际项目中,了解Servlet的工作原理有助于更好地...

    javax-servlet源码包和jar文件

    7. **源码分析**: 拥有源码意味着可以直接查看这些类的实现细节,理解它们如何协同工作,这对于深入学习Servlet原理,优化代码性能,甚至开发自己的Servlet框架都非常有益。 通过深入研究`javax.servlet`和`javax....

    tomcat源码(包括servlet源码)jar格式

    该文件是tomcat6.0中lib包中jar包的源码,已被本人打包成为jar文件,是研究servlet源码比不可少的资料。由本人亲手试过,真心好用!!

    韩顺平servlet部分的源码文件

    接着,我们来看源码文件中的关键点。韩顺平老师的源码可能会包含以下内容: 1. **Servlet配置**:在`web.xml`文件中,Servlet会被声明并配置,包括Servlet的类名、URL映射等。例如: ```xml &lt;servlet&gt; &lt;servlet-...

Global site tag (gtag.js) - Google Analytics