对于一个Javaweb项目,在没有特殊配置的情况下,该项目中每个servlet是单例的。但是出于性能考虑,servlet容器必须以多线程的方式去处理http请求。这种多线程与单例之间的矛盾必然会引出一个问题,那就是线程安全。为了保证线程安全,在servlet对象当中不建议使用成员变量,在操作成员变量时也建议加上synchronize关键字。
同样的矛盾也存在与spring当中,一个被@Controller注解修饰的类对于beanfactory是单例的,不过奇怪的是我们可以使用@Autowired注解为一个Controller类配置request,response等成员变量。很显然,request和response必然会存在于多个线程中,而Controller类是单例的,这种做法似乎也存在线程安全问题。但是spring依旧允许这种配置方式的存在,原因是什么?
首先说一下结论,spring中使用@Autowired注解为一个类配置request,response等成员变量是没有问题的。spring基于以下四个技术和具体事实成功避免了线程安全问题
1.在Tomcat和Jetty中,request和response对象对于线程单例的;
2.基于Invocationhandler的动态代理;
3.ThreadLoacl是从当前线程中获取对象;
4.在web项目中,可以使用Listener监听并处理http请求;
首先解释一下1
为了提高处理效率,Tomcat和Jetty均使用react模式多线程的处理http请求。而一个处理线程会包含一个request和response对象。当请求发起时,request对象装载请求参数,当请求返回时,response输出缓冲区的数据,request则清空其加载的参数,然后等待处理下一次请求。换句话说,只要这个处理线程存在,这两个对象永远为null,更不会被垃圾回收机制处理。servlet规范中,要求每个request和response对象只能在servlet的service方法中有效,但是同时也允许容器重复使用这些对象。
一句话总结:request对象和response对象在一个处理线程中是唯一的