Servlet

来源:互联网 发布:手机淘宝淘宝客 编辑:程序博客网 时间:2024/06/10 20:23

一、servlet(这里主要指HttpServlet)生命周期只有两种状态:未创建状态与初始化状态。这两种状态转换主要靠3个方法来进行控制:init() ,service(),destory().

init():此方法会接受到一个servletConfig类型的参数,根据此参数可以获得servlet的一些信息,从而初始化servlet.

service():用于处理客户端传来的请求,根据HTTP请求方法,将请求分发给doGet(),doPost()方法。

destory():用于释放与servlet相关的资源。

web应用的初始化工作主要是解析web.xml文件,servlet被包装成context容器中的StandardWrapper,这里有个疑问,为什么要将 Servlet 包装成 StandardWrapper 而不直接是 Servlet 对象。这里 StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 为一个独立的 web 开发标准,不应该强耦合在 Tomcat 中。除了将 Servlet 包装成 StandardWrapper 并作为子容器添加到 Context 中,其它的所有 web.xml 属性都被解析到 Context 中,所以说 Context 容器才是真正运行 Servlet 的 Servlet 容器。一个 Web 应用对应一个 Context 容器,容器的配置属性由应用的 web.xml 指定,这样我们就能理解 web.xml 到底起到什么作用了。

前面已经完成了 Servlet 的解析工作,并且被包装成 StandardWrapper 添加在 Context 容器中,但是它仍然不能为我们工作,它还没有被实例化。

如果 Servlet 的 load-on-startup 配置项大于 0,那么在 Context 容器启动的时候就会被实例化。创建 Servlet 实例的方法是从 Wrapper. loadServlet 开始的。loadServlet 方法要完成的就是获取 servletClass 然后把它交给 InstanceManager 去创建一个基于 servletClass.class 的对象。

初始化 Servlet 在 StandardWrapper 的 initServlet 方法中,这个方法很简单就是调用 Servlet 的 init 的方法,同时把包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig 传入。


在多线程情况下,servlet是线程不安全的,采用多线程来处理多个请求同时访问,Tomcat容器维护了一个线程池来服务请求.线程池实际上是等待执行代码的一组线程叫做工作组线程(Worker Thread),Tomcat容器使用一个调度线程来管理工作组线程(Dispatcher Thead)。当容器收到请求时,调度线程会调用工作组线程来执行对应servlet的service方法.当有新的请求时,会调度另一个工作线程执行对应servlet的service方法,容器不关心是不是相同的servlet.这样这个servlet会在多线程下执行service方法.

怎么设计线程安全的servlet类呢?由于多线程不共享局部变量,因此可以将servlet实例变量定义为局部变量使用.


二、Spring MVC中Servlet一共有三个层次,即自身创建时分3个层次:

HttpServletBean:将Servlet中配置的参数设置到相应的属性中。

FrameworkServlet:初始化webApplicationContext,即获取spring的根容器WebApplicationContext、将WebApplicationContext设置到ServletContext中等一些事情。

DispatcherServlet:初始化身的9个组件,初始化方式分两步:首先通过context.getBean在容器中按注册时的名称或类型查找,找不到就调用getDefaultStrategy按照类型获取默认的组件。这里的context指WebApplicationContext。


三、Spring MVC处理请求过程

请求首先通过FrameworkServlet进行处理,其将所有需要自己处理的请求都交给了processRequest方法进行统一处理。这个方法中的核心部分是doService()方法,是个模板方法,由DispatcherServlet具体实现。

DispatcherServlet执行处理的入口方法是doService,doservice将请求交给了doDispatch进行处理,在这之前doService

会对request进行快照备份和设置一些属性。

doDispatch方法执行大概流程:

1、调用HandlerMapping组件的getHandler方法,根据request找到Handler(处理器)和Intercepor。

2、调用getHandlerAdapter方法,根据Handler遍历找到HandlerAdapter(适配器)。

3、HandlerAdapter使用Handler处理请求并返回视图。

4、若有异常,HandlerExceptionResolver组件根据异常设置ModelAndView。

5、调用ViewResolver组件的resolveViewName方法,将String类型的视图名和Locale解析为View类型的视图。ViewResolver找到渲染所用的模板和视图类型进行渲染,具体渲染的过程交给不同的视图自己完成。如果没有视图名,则调用RequestToViewNameTranslator组件从request获取viewName。解析视图所用的Locale由LocaleResolver组件从request解析出来。

6、调用View的render方法进行渲染页面。