Web 容器: 早期的web应用主要是浏览静态页面,想Apache, Nginx 都是向浏览器返回html文件,然后浏览器解析并展示html文件。
后来随着网络的发展,人们希望可以有更多的交互,即希望服务器不是简单的返回一个html,而是可以根据用于的输入,动态的生成html来和用户交互,所以这时我们就需要在服务器端再部署一下java程序来和用户交互,这些程序就是servlet,但是servlet 没有main函数,不能独立运行,需要servlet容器来对他们进行调度,所以就有了servlet容器。 像tomcat, jetty其实就是 HTTP服务器+ servlet容器
Apache是一个HTTP服务器,而Tomcat或者Jetty是一个HTTP服务器+Servlet容器。HTTP服务器与Servlet容器的功能界限是:你可以把HTTP服务器想象成前台的接待,负责网络通信和解析请求,而Servlet容器是业务部门,负责处理业务请求。
如下图所示,HTTP服务器,负责获取客户端请求,然后将请求解析并发送给Servlet服务器,servlet容器决定具体调用那个servlet来执行该请求。servlet怎么知道调用那个类的那个方法来处理请求呢?怎么知道每个方法的名字是啥,参数是啥呢? 很现实servlet容器和servlet之间必须有个接口来统一调度,这个接口就是servlet接口。
servlet接口如下
public interface Servlet {
void init(ServletConfig config) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
String getServletInfo();
void destroy();
}
其中的init 方法可以在启动servlet的时候初始化一些资源; destroy则是在servlet销毁时释放一些资源。
getServletConfig则指夹在我们在web.xml中配置的一些参数。
service则是实现具体业务逻辑的地方。
有接口通常就会有一个抽象类来实现一些通用逻辑,这里的抽象类则是GenericServlet. 虽然servlet并不在意请求时通过什么协议传过来的,结果需要使用什么协议传出去,但是通常都是基于HTTP协议,所以为了方便使用这里还是实现了HTTPServlet,以加入http特性,我们乳沟要实现http相关的servlet可以直接继承该子类,然后重新doGet, doPost即可,大大简化了我们编程。
下面我们再来看一下请求处理过程:
HTTP服务器拿到客户端请求之后将其解析打包成一个ServletRequest,然后调用Servlet的service方法,将请求传递给Servlet容器, Servelt容器,根据提前制定好的映射规则,根据请求中的URL 调用指定的servlet,如果servlet还没有被加载,则通过反射机制将其加载到Servlet容器中,然后调用。调用完成之后将结果打包成ServletResponse返给HTTP服务器,http服务器在将其解析打包成满足http协议的数据包发送给客户端。
那么我们一定很好奇,servlet容器怎么知道去哪里找我们的servlet类呢?我们通常是以web服务的形式来注册servlet,web应用程序通常有制定的目录结构,如果大家都遵从这个目录结构,那servlet容器就知道去哪里找我们的servlet类了。
web应用程序的目录结构如下
通常一个web应用程序会包含多个servlet。 servlet规范中定义了一个serveltContext来对应这个web应用程序。其中可以存放一些公共信息,servlet之间也可以通过它来进行交互。