servlet生命周期

一、什么是servlet

  • servlet是java写的服务端程序,交互式的浏览修改数据,生成动态web内容。通俗讲,它就是java web开发的基础。
  • Servlet API中定义了70中类型,可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
  • 所有的Servlet就是直接或间接实现 javax.servlet接口。Servlet 接口定义了 Servlet与Servlet容器之间的契约:Servlet容器将Servlet载入内存,并在Servlet 实例上调用具体方法,在一个应用中,每种Servlet类型只能有一个实例(Servlet容器默认采用单实例多线程的方式来处理请求), Servlet 不是线程安全的,不能有成员变量,不要有synchorize 的方法(http://blog.chinaunix.net/uid-21209537-id-4304323.html)
  • org.springframework.web.servlet.DispatcherServlet是SpringMVC的核心,SpringMVC请求的第一站是DispatcherServlet,充当前端控制器角色,DispatcherServlet会查询一个或多个处理器映射(handler mapping)并根据请求所携带的URL信息进行决策,将请求发送给哪个SpringMVC控制器(controller),controller 定义视图、打包数据返回给DispatcherServlet, DispatcherServlet 通过视图解析器(view resolver)来将逻辑视图名匹配为一个特定的视图实现,然后数据模型以视图形式响应给客户,完成整个请求流程。
  • Spring boot自动注册DispatcherServlet。

二、Servlet生命周期

  1. 第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。
  2. Servlet 容器加载并实例化 Servlet,调用init()方法初始化,仅执行一次。
  3. Servlet 容器创建每个线程都调用唯一Servlet 实例的 service() 方法(service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法)。
  4. Servlet实例被标记为垃圾回收,调用destroy(),结束生命周期。

三、 Servlet的线程工作模型
在这里插入图片描述

  1. Servlet收到客户端的具体请求,Servlet首先会把请求发送给调度器,由调度器进行统一的请求派发,调度器会从线程池中选取一个工作主线程;
  2. 调度器把请求派发给该线程,由该线程的执行servlet的service方法;
  3. 这个线程正在执行的时候,servlet容器又收到另一个请求,调度器会从线程池中选取另外一个工作主线程来服务这个新的请求,容器并不关心请求访问的是同一个servlet还是另外一个servlet;
  4. 容器收到同一个servlet的多个请求时,这个servlet的service方法将会在多线程中并发执行;
  5. 线程使用完之后,就会把线程放回线程池中,如果说线程池中的线程都在进行服务,有新的请求,一般情况下这些请求会做排队处理,servlet容器也能配置servlet的一个最大的请求排队数量,假如超过这个数量,servlet就会拒绝相应的servlet请求。

四、 Servlet并发处理的特点:

  1. 单实例:
    从servlet生命周期中可以知道,对于具体的某个servlet来说,servlet只会初始化一次,调用一次init(),也就是说,在整个servlet容器中只会有一个servlet的实例对象,不管我们有多少请求都是针对同一个servlet实例对象。
  2. 多线程:
    从线程的模型可以看到,请求的处理由多个工作线程来完成的,可以同时进行处理,同时处理的数量跟线程池的大小有关系。
  3. 线程不安全:
    servlet是单个实例,但又是多个线程共用实例对象,意味着servlet容器在多个线程访问同一个servlet的实例对象是没有默认加锁操作的,照成线程不安全,因为我们可能出现某一个线程正在修改servlet的实例状态,但是另外一个线程又需要读取servlet的线程状态,这个时候就会出现数据不一致的情况。

四、Servlet线程安全注意要点

  1. 变量的线程安全:
    A), 变量本地化:也就是说尽量使用局部变量,因为多线程并不共享局部变量。
    B),使用同步块synchronized:就是对我们的一些代码进行加锁的处理,在做加锁处理的时候应该注意,尽可能的缩小synchronized的代码块的范围
    C),最好不要再service方法上增加关键字,这样会对性能的损耗比较大。
  2. 属性的线程安全:
    A),ServletContext线程不安全:因为ServletContext是可以多线程读取它的属性,所以线程不安全,那我们在对sevletContext属性进行读写的时候,就需要注意做一些同步的处理
    B),HttpSession理论上线程安全:HttpSession属性是在用户会话期间存在的,那只能在处理同一个Session请求的线程中被访问,那Session对象的属性访问理论上是安全的,当用户打开多个属于同一个进程的浏览器窗口的时候,在这些窗口的访问属于同一个Session会出现多个请求,需要多个线程来进行处理,也会照成多个线程读写属性的问题,这个时候我们还会需要对Session的属性进行一个同步处理。所以是理论上的线程安全
    C),ServletRequst线程安全:对于每一个请求只能由一个线程进行处理,所以ServletRequst对象只能在同一个线程中被访问。
  3. 避免在Servlet中创建线程
    因为Servlet本身就是多线程进行处理的,如果在Servlet再创建一些线程,就会导致执行情况变得非常复杂,出现一些多线程安全的问题
  4. 多个Servlet访问外部对象加锁

五、Springboot中的DispatcherServlet
springboot在自动配置springMVC的时候,自动通过org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration并利用DispatherServletRegistrationBean和DisPatherservletPath来注册DispatcherServlet。
@Order
自定义mapping配置可:
1), 在application.properties 文件中增加 server.servlet-path= /api/*;
2),注入一个新的ServeletRegistryBean用于映射新的url;

//自动注入spring boot默认的上传配置
@Autowired
private MultipartConfigElement multipartConfigElement;
@Autowired
private DispatcherServlet dispatcherServlet;
@Bean
public ServletRegistrationBean apiServlet() {
    ServletRegistrationBean bean = new ServletRegistrationBean(dispatcherServlet);
    //注入上传配置到自己注册的ServletRegistrationBean
    bean.addUrlMappings("/api/*");
    bean.setMultipartConfig(multipartConfigElement);
    bean.setName("apiServlet");
    return bean;
}
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值