为何需要Web容器
Web服务器本身主要用于支持http协议,包括监听和相应http请求。web服务器一般处理静态的请求,如文件系统中的静态文件。web容器则是为web相关的组件提供运行环境,可以从‘容器’一词稍微理解其含义。
简单说,web服务器和web容器本身只是一个平台的应用程序而已。因此,为了理解其作用,假设在没有web服务器和web容器的情况下,我们如何响应客户端请求。从网络编程的角度来看,我们需要:
new一个ServerSocket监听在一个端口上
调用accept等待客户端连接
有连接了返回一个和客户端相对应的Socket对象用于客户端和服务器之间的通信
为了能够并发的处理请求,还需要多线程的支持,对请求排队,开多个线程处理队列中的请求或者每个请求开一个线程
对于web应用来说,还要分析Http协议,处理http数据包,根据http数据包中的数据对客户端做出响应
从上可以看出,在没有web服务器和web容器的情况下,开发一个web应用是非常艰难的,因此,web服务器和web容器帮我们把这些通用的事情都做好了,只需要在已有的框架内,关注于本身的业务进行开发。
那web容器本身为何物,从容器一词可以看出,其主要提供一个运行的环境。web应用程序本身是没有main函数的,主要通过请求触发的方式执行。如果说web应用只关注于业务本身,那其从何处开始执行,以及对于http数据包本身的分析包括请求参数、协议版本、数据类型等等,都需要一个完整的执行环境,这个东西就是web容器。就Servlet来说,Servlet的开发从继承HttpServlet开始,实现其doPost和doGet函数处理请求。但是两个函数本身的参数都是HttpServletRequest和HttpServletResponse对象,而且HttpRequest对象已经包含了http请求中的参数字段,这些对象就是Web容器提供的。还有Servlet对象本身的构建也不需要关心,容器会加载Servlet类,调用构造函数、init函数,和最后destroy。其提供了对Servlet整个生命周期的管理。
Servlet生命周期
Servlet用于处理Http请求,在Web开发的MVC模式中,担当控制器的角色。用于调用具体的业务逻辑对象处理业务逻辑,然后将处理结果转发给View层,通过Web服务器发送给客户端。
之前说过,Web容器负责管理Servlet的生命周期,Servlet生命周期本身如下图所示:
在Servlet加载之前,容器先加载Servlet的class文件、调用其构造函数,然后进入Servlet真正的生命周期,init-》service-》destroy,容器会保证service方法执行之前,init方法已经完成,使其在提供服务之前,进行相应的初始化。容器会根据不同的Servlet配置,在不同的时间段加载Servlet,当Servlet配置了load-on-startup时,会在服务器启动时进行加载,这种方式可以用于初始化一些全局环境。当没有配置load-on-startup时,在第一次请求到来是,容器会加载Servlet响应请求。Servlet的一生主要在service中度过,用于响应客户端的服务,这个函数会根据不同的请求函数对请求进行分发,doPost对POST请求进行处理,doGet对GET请求进行处理。当服务器关闭时,容器会调用Servlet的destroy方法,保证在Servlet结束之前,释放其持有的资源。
那么容器在servlet的生命周期和请求响应过程中干些什么呢,如之前说的,其会分析Http数据包,打包成HttpServletRequest和HttpServletResponse对象,然后执行service方法。其实,容器对于每一个Http请求都会新建一个线程,处理请求。线程、request、response和service就组成了一个客户端从请求到响应的环境。当请求结束时,容器会清理request和response对象,结束线程或者回收其到线程池。从这里可以看出,每个请求虽然在单独的线程中运行,但是Servlet本身并非线程安全。从Servlet生命周期分析中可以看出,每一个Servlet对象在整个web应用的生命中只有一个,对于每一个请求,在不同的线程中执行其service方法而已。
从URL到Servlet
客户端的请求一般都是一个URL,如何从URL映射到Servlet,然后加载(如果需要)初始化对应的Servlet呢。每一个Web项目都需要web.xml对其进行配置,其中就包括了<servlet>,<servlet-mapping>两个标签。<servlet>标签用于从servlet的class到servlet-name的映射,servlet-name是一个只用于web.xml配置中使用的一个名字,其可以随便命名,用于URL和对于的class直接解耦。<serlvet-mapping>用于从url到<servlet-mapping>的映射。容器从URL到Servlet的映射就可以通过分析web.xml来实现。先从<servlet-mapping>找到从URL到servlet-name,然后在从servlet-name找到对应的class的全局限定名。找到了class之后,如果需要加载则会加载类,并出行上述的生命周期过程,如果已经加载过了,容器直接执行其service方法,处理请求。这就是从URL到Servlet到客户端响应的过程。其中容器全权负责Servlet的生命周期。
本文出自 “深思JavaEE” 博客,请务必保留此出处http://xjava.blog.51cto.com/2949562/1408531