HttpServletRequest
是由如tomcat這種Servlet容器創(chuàng)建的慎颗。
Tomcat 創(chuàng)建的 Request 和 Response 的類結(jié)構(gòu)圖粟关。
至于這個HttpServletRequest
是怎么傳到你對應(yīng)的controller方法內(nèi)的,實(shí)際上就是SpringMVC里面的DispatchServlet
起的作用亲善。這里先不展開设易,下面再討論,先看一張圖蛹头。
得到HttpServletRequest的三種方式
方式一:Controller方法參數(shù)
在Controller
的方法參數(shù)上寫上HttpServletRequest
顿肺,這樣每次請求過來得到就是對應(yīng)的HttpServletRequest
。
@GetMapping("/test")
public void test(HttpServletRequest request) {}
方式二:從RequestContextHolder上下文獲取
// 從請求上下文里獲取Request對象
ServletRequestAttributes requestAttributes = ServletRequestAttributes.class.
cast(RequestContextHolder.getRequestAttributes());
HttpServletRequest contextRequest = requestAttributes.getRequest();
方式三:依賴注入@Autowired
@Autowired
HttpServletRequest req;
@GetMapping("/test")
public void test(HttpServletRequest request) {}
注入的request何處來?
發(fā)現(xiàn)是注入其實(shí)是往WebApplicationContextUtils通過RequestObjectFactory拿值渣蜗,跟蹤
返回的是RequestContextHolder里的值. 追蹤RequestContextHolder
每次返回的其實(shí)是屠尊, RequestAttributes的實(shí)現(xiàn)類ServletWebRequest(ServletRequestAttributes)里的request. 因?yàn)镽equestAttributes是屬于threadLocal的,所以注入的request也是線程安全的了
2, spring何時設(shè)置的request對象?
HttpServlet實(shí)現(xiàn)類 FrameworkServlet-> service()->processRequst()
每次請求都會往里面設(shè)置最新的request, 設(shè)值
================================================================
我們可以在Spring的bean中輕松的注入HttpServletRequest耕拷,使用@Autowired HttpServletRequest request;就可以了讼昆。
但是,為什么我們可以直接這樣用呢骚烧?
原因肯定是Spring在容器初始化的時候就將HttpServletRequest注冊到了容器中浸赫。
那么我們就查原碼,發(fā)現(xiàn)在WebApplicationContextUtils.registerWebApplicationScopes(ConfigurableListableBeanFactory, ServletContext)中實(shí)現(xiàn)了這個功能赃绊。
這個方法是在AbstractApplicationContext.refresh()中進(jìn)行調(diào)用的掺炭,也就是在Spring容器初始化的時候,將web相關(guān)的對象注冊到了容器中凭戴。
具體可以看下面的原碼圖片:
附:
1. Spring能實(shí)現(xiàn)在多線程環(huán)境下涧狮,將各個線程的request進(jìn)行隔離,且準(zhǔn)確無誤的進(jìn)行注入么夫,奧秘就是ThreadLocal
2. Spring中還可以直接注入ApplicationContext