Web服务器,Servlet容器
Servlet应用程序:我们自己编写的处理请求,响应的代码(doGet()和doPost()方法)。
Web服务器:使用HTTP协议来传输数据。最简单的一种情况是,用户在浏览器中输入一个URL,然后就能获取网页进行阅览。因此,服务器完成的工作就是发送网页至客户浏览器。传输过程遵循HTTP协议,它指明了请求(request)消息和响应(response)消息的格式。例如我们常用的Tomcat服务器。
Servlet容器
- Servlet容器也叫做Servlet引擎,是Web服务器或应用程序服务器的一部分。
- Servlet容器的基本思想是在服务器端使用Java来动态生成网页。因此,Servlet容器是Web服务器和Servlet进行交互的必不可少的组件。
- 用于在发送的请求和响应之上提供网络服务,因为Servlet应用程序没有main方法,不能独立运行,它必须被部署到Servlet容器中,由容器来实例化和调用 Servlet的方法(如doGet()和doPost()),Servlet容器在Servlet的生命周期内包容和管理Servlet。
- 在Tomcat中包含有Servlet容器
Web服务器和Servlet容器处理请求过程
- Web服务器接收到Http请求
- Web服务器将请求转发给Servlet容器,然后Servlet容器产生两个对象:
请求对象(HttpServletRequest),响应对象(HttpServletResponce) - 如果容器中不存在所需的servlet,容器就会检索servlet,并将其加载到容器的地址空间中,这里Servlet容器会在第一次加载时,将应用程序中的所有Servlet映射到地址空间中。
- Servlet容器根据url找到目标Servlet,且创建一个线程,并且将刚才创建的请求对象和响应对象传递给线程
- 容器调用Servlet的init()方法对Servlet进行初始化(该方法只会在Servlet第一次被载入时调用)
- 容器调用Servlet的service()方法来处理Http请求,并传入,据请求类型调用doGet()或doPost()方法
- Web服务器将动态生成的结果返回到正确的地址,然后创建的线程被销毁或者放到线程池中。
servlet生命周期
Servlet编程需要使用到javax.servlet和javax.servlet.http两个包下的接口和类,在所有的类和接口中,javax.servlet.servlet接口最为重要。所有的Servlet程序都必须实现该接口或继承自实现该接口的类。主要方法包括:
/*
初始化方法,当Servlet容器实例化某个servlet类后,
Servlet容器将会调用其init()方法进行初始化。
Servlet容器只会调用一次init()方法,初始化代码块比如连接数据库,设置一些初始值等。
*/
public void init(ServletConfig config) throws ServletException{
...
}
/*
处理请求方法,Servlet容器为每个客户端创建一个线程,
并且这些线程将会同步的调用service()方法,
将请求对象(HttpServletRequest),响应对象(HttpServletResponce)参数传递进来
*/
public void service(ServletRequest request, ServletResponse response) Throws ServletException,java.io.IOException{
...
}
/*
销毁方法,当Servlet容器关闭或Servlet容器要释放内存时,才会将servlet实例移除,而且只
有当servlet实例的service()方法中的所有线程都退出或执行超时后,才会调用destroy()方法。
*/
public void destroy(){
...
}
加载Servlet的过程
首先注意到,创建每个servlet都有一个@WebServlet注解,它是Servlet 3.0中,可以使用标注(Annotation)来告知容器哪些Servlet会提供服务以及额外信息。
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
...
}
上面提到Servlet的地址空间,它其实是一张key-value表,例如:
键 | 值 |
---|---|
hello | HelloServlet |
key2 | value2Servlet |
key3 | value3Servlet |
… | … |
上面的@WebServlet告诉容器,如果请求的URL是"/hello",则由HelloServlet的实例提供服务。可以使用@WebServlet提供更多信息。
过程:
- 当应用程序启动后,事实上并没有创建所有的Servlet实例。容器会根据请求去地址空间的key-value表中找对应的servlet。
- 如果容器中不存在所需的servlet,容器就会检索servlet,并将其加载到容器的地址空间中。如果没有则会报错。
- 容器会在首次请求需要某个Servlet服务时,才将对应的Servlet类实例化、进行初始化操作,然后再处理请求。
- 这意味着第一次请求该Servlet的客户端,必须等待Servlet类实例化、进行初始动作所必须花费的时间,才真正得到请求的处理。
通过反射创建Servlet实例对象
Servlet容器创建servlet实例对象是根据反射来创建的。
- 通过地址空间,找到url对应的Servlet类的名称
- 通过反射,可以先不关心类的属性和方法的参数,获得对应servlet的实例对象,然后给它的属性逐一赋值,再把方法绑定到其所属方法内。
- 每个servlet都是单实例多线程的。每个servlet类只被实例化一次,这样的目的是为了提高效率,多用户访问时,为每个用户生成一个线程。用户通过生成的线程完成相应的操作。