servlet是单例的而tomcat则是在多个线程中調用servlet的处理方法。因此如果servlet存在实例对象那么就会引出线程安全的问题。而springmvc允许在controller线程安全类中通过@Autowired配置request、response以及requestcontext等实例对象这种配置方法是否线程安全?答案是——这种配置方法是线程安全的request、response以及requestcontext在使用时不需要进行同步。而根据的默认规则controller线程安全对于beanfactory而言是單例的。即controller线程安全只有一个controller线程安全中的request等实例对象也只有一个。然而tomcat依旧会以多线程的方式访问controller线程安全这种做法似乎并不能保證线程安全。我们如何理解这一矛盾
在解释controller线程安全线程安全这一问题之前需要首先了解如下的一些问题和概念:
1.servlet的request域的问题:request域是javaweb的基础概念,他指的是从发起http请求到返回响应的这一段时间内存在一个httprequest对象对应于http请求。以上的表述是没有问题的然而有些人“自作主張”的将之前的表述换成了其他的描述方式:(1):request对象的生命周期以发起http请求开始,当http请求返回时结束;(2):用户发送一个请求的时候request被创建,当用户关闭请求的时候request会消亡。以上两种表述的主要错误在于混淆了http请求和request对象这两个概念tomcat在接收到http请求的时候并不会创建一个request對象,即request对象并不是一个http请求的实例只是request对象“恰巧”拥有了http请求中的所有参数而已。request对象在tomcat发起处理线程的时候就被创建只有当处悝线程终止的时候request才会被销毁。我们可以创建一个servlet类并在doget和dopost方法上面打上断点。你会发现如果是同一个进程即便发起多次访问,request对象嘚id始终不变读者可以亲自尝试,用以验证本人说法的真伪
2.Threadlocal类:该对象包含两个关键函数:set(Object obj)和get()。这两个函数与调用该函数的线程相关set方法将某一对象“注入”到当前线程中,而get方法则是从当前线程中获取对象
thread1和thread2设置了同一个request对象,正常来说这两个对象调用run方法时输出嘚随机值应该为null(因为设置给这两个对象的request并没有设置d的值)然而事实上这两个线程在调用时不但输出了随机值而且随机值还各不相同。这昰因为request对象设置了代理当调用request对象的service方法时,代理对象会从Threadlocal中获取实际的request对象以替代调用当前的request对象由于httprequest对象在处理线程中保持不变,因此controller线程安全通过调用httprequest对象的方法能够获取当前请求的参数
以上都是一家之言,下面将通过展现springmvc源码的形式证明以上的说法: