Controller中加參數
@Controller
public class TestController {
@RequestMapping("/test")
public void test(HttpServletRequest request) {
......
}
}
Controller中獲取request對象后,如果要在其他方法中(如service方法、工具類方法等)使用request對象,需要在調用這些方法時將request對象作為參數傳入
此時request對象是方法參數,相當于局部變量,毫無疑問是線程安全的。
自動注入
@Controller
public class TestController{
@Autowired
private HttpServletRequest request; //自動注入request
@RequestMapping("/test")
public void test() throws InterruptedException{
......
}
}
使用這種方式,當Bean(本例的TestController)初始化時,Spring并沒有注入一個request對象,而是注入了一個代理(proxy);當Bean中需要使用request對象時,通過該代理獲取request對象。request實際上是一個代理:代理的實現參見AutowireUtils的內部類ObjectFactoryDelegatingInvocationHandler。
調用request的方法method時,實際上是調用了由objectFactory.getObject()生成的對象的method方法;objectFactory.getObject()生成的對象才是真正的request對象。
objectFactory的類型為WebApplicationContextUtils的內部類RequestObjectFactory;而RequestObjectFactory要獲得request對象需要先調用currentRequestAttributes()方法獲得RequestAttributes對象,生成RequestAttributes對象的核心代碼在類RequestContextHolder中,生成的RequestAttributes對象是線程局部變量(ThreadLocal),因此request對象也是線程局部變量;這就保證了request對象的線程安全性。
基類中自動注入
public class BaseController {
@Autowired
protected HttpServletRequest request;
}
@Controller
public class TestController extends BaseController {
}
與方法2相比,避免了在不同的Controller中重復注入request;但是考慮到java只允許繼承一個基類,所以如果Controller需要繼承其他類時,該方法便不再好用。
手動調用
@Controller
public class TestController {
@RequestMapping("/test")
public void test() throws InterruptedException {
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
.......
}
}
通過自動注入實現與通過手動方法調用實現原理差不多。因此本方法也是線程安全的。
優點:可以在非Bean中直接獲取。缺點:如果使用的地方較多,代碼非常繁瑣;因此可以與其他方法配合使用。
@ModelAttribute方法
@Controller
public class TestController {
private HttpServletRequest request; 此處線程不安全
@ModelAttribute
public void bindRequest(HttpServletRequest request) {
this.request = request; 此處request線程安全
}
@RequestMapping("/test")
public void test() throws InterruptedException {
......
}
}
@ModelAttribute注解用在Controller中修飾方法時,其作用是Controller中的每個@RequestMapping方法執行前,該方法都會執行。bindRequest()的作用是在test()執行前為request對象賦值。雖然bindRequest()中的參數request本身是線程安全的,但由于TestController是單例的,request作為TestController的一個域,無法保證線程安全。

浙公網安備 33010602011771號