我们这里使用的是Apache的Tomcat工具,而Tomcat实现了Servlet
想要了解Servlet处理请求的原理,首先需要了解Servlet的继承结构以及生命周期
Servlet继承结构:
Servlet接口
- init(),创建Servlet对象后立即调用该方法完成一些初始化工作。
- service(),处理客户端请求,执行业务操作,利用响应对象响应客户端请求。需要两个参数:第一个参数是ServletRequest,第二个参数是ServletResponse
- destroy(),在销毁Servlet对象之前调用该方法,释放资源。
- getServletConfig(),ServletConfig是容器向servlet传递参数的载体。
- getServletInfo(),获取servlet相关信息。
GenericServlet抽象类
GenericServlet是实现了Servlet接口的抽象类。在GenericServlet中进一步的定义了Servlet接口的具体实现,其设计的目的是为了和应用层协议解耦,在GenericServlet中包含一个Service抽象方法。
值得注意的是:GenericServlet抽象类并没有实现service(),因为GenericServlet抽象类就是为了解耦合的,当有不同协议的Servlet需要继承GenericServlet,如果在GenericServlet中就实现了service()方法,而service方法就是用来处理请求并且响应给客户端的,那请求中有请求行,请求行包含了协议,那支持的协议有那么多种,有http协议有https协议等等,那么他应该基于哪个协议去实现这个方法呢?
HttpServlet类
继承自 GenericServlet,针对于处理 HTTP 协议的请求所定制。在 HttpServlet的service() 方法中已经把 ServletReuqest 和 ServletResponse 转为 HttpServletRequest 和 HttpServletResponse。 直接使用 HttpServletRequest 和 HttpServletResponse, 不再需要强转。实际开发中, 直接继承 HttpServlet, 并根据请求方式复写 doXxx() 方法即可。
Servlet生命周期:
Servlet的生命周期是由容器管理的,分别经历三各阶段:
init():初始化
service():服务
destroy():销毁
1、当客户端服务器第一次请求Servlet时,容器会实例化这个Servlet
2、然后调用init方法,创建一个新的线程,一个线程就代表一个Servlet,然后执行service()方法处理请求
3、service()方法执行过后容器不会销毁这个Servlet而是做缓存处理,当客户端再次请求这个Servlet的时候,容器会从缓存中直接找到这个Servlet对象,并再一次在新的线程中执行service()
4、当容器在销毁Servlet之前调用一次destroy方法。
Servlet处理请求的原理(以HttpServlet实现类为例)
当浏览器基于get方式请求我们创建Servlet时,我们自定义的Servlet中的doGet方法会被执行。doGet方法能够被执行并处理get请求的原因是:
1、Tomcat在启动时会解析web工程中的WEB-INF目录中的web.xml文件,在web.xml文件中将servlet和url进行了关联
2、Tomcat通过对请求的解析可以获取请求资源的URL,然后找到该URL绑定的Servlet并做实例化处理(注意Servlet只会被实例一次,如果在缓存中可以找到这个Servlet就不会实例化)
3、在实例化时会使用Servlet作为引用类型进行定义,创建我们自定义的继承了HttpServlet的类,并调用一次init()方法,由于GenericServlet中实现了该方法,所以最终执行的是GenericServlet中的init()方法(GenericServlet中的init方法是一个空方法)
4、实例化过后在新的线程中调用service()方法,由于在HttpServlet中重写了service(),所以调用的是HttpServlet类中的service(),而在HttpServlet类中的service()方法已经将原本Servlet接口中的service()的参数强转为了HttpServletRequest和HttpServletResponse(不同的实现类会强转为不同的类型)
5、在service()中通过request.getMethod()获取请求方式进行判断,如果请求方式是Get方式那么调用doGet(),如果是Post方式那么调用doPost(),
都需要两个参数(不同的实现类会需要的是不同的参数类型):
第一个参数HttpServletRequest,
第二个参数是HttpServletResponse
6、执行我们编写的继承了HttpServlet类的自定义类中对应请求方式的方法,而这个方法的作用就是响应