[英]Inject HttpServletRequest into Controller
據我所知,默認情況下是Spring MVC單例中的控制器。 HttpServletRequest
將offen傳遞給控制器處理程序方法。 沒關系,雖然HttpServletRequest
是請求范圍的,但是我經常看到HttpServletRequest
被@Autowired
進入控制器字段,如下所示:
@Controller("CMSProductComponentController")
@RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
@Autowired
private HttpServletRequest request;
}
這可能是個問題嗎? 還有一個更籠統的問題:如果將要求范圍內的組件注入單例,會發生什么?
不,對於HttpServletRequest
來說這不是問題,對於其他請求范圍的Bean也不應如此。 基本上,Spring將生成一個代理HttpServletRequest
,該代理包裝了某種ObjectFactory
(用於HttpServletRequest
RequestObjectFactory
)(YMMV),該對象知道如何檢索實際實例。 當您使用此代理的任何方法時,它們將委托給該實例。
而且,這是懶惰完成的,因此它不會在初始化時失敗。 但是,如果在沒有可用請求時嘗試使用Bean(或者未注冊RequestScope
),它將失敗。
以下是對評論的回應,並進行了一般性的說明。
關於@Scope
或XML等效項的proxy-mode
屬性,默認值為 ScopedProxyMode.NO
。 但是,正如javadoc所述
當與非單作用域實例一起使用時,此代理模式通常不是有用的,如果將其用作依賴項,則應優先使用INTERFACES或TARGET_CLASS代理模式。
對於請求范圍的Bean,此proxy-mode
值將不起作用 。 您需要根據所需的配置使用INTERFACES
或TARGET_CLASS
。
將scope
設置為request
(使用常量WebApplicationContext.SCOPE_REQUEST
),Spring將使用RequestScope
依賴於線程綁定的
RequestAttributes
實例,該實例可以通過RequestContextListener
,RequestContextFilter
或DispatcherServlet
導出。
讓我們舉一個簡單的例子
@Component
@Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
@Autowired
private RequestScopedBean bean;
Spring將生成兩個 bean定義:一個用於注入的bean,一個單例,一個用於在每個請求中生成的請求范圍的bean。
通過這些bean定義,Spring會將單例初始化為具有目標類類型的代理。 在此示例中,這就是RequestScopedBean
。 代理將包含它需要產生或在需要時返回實際bean所需的狀態,即。 在代理上調用方法時。 例如,當
bean.method();
叫做。
此狀態基本上是對基礎BeanFactory
的引用以及請求范圍的Bean定義的名稱。 它將使用這兩個生成一個新bean,然后在該實例上調用method()
。
文檔說明
Spring IoC容器不僅管理對象(bean)的實例化,而且還管理協作者(或依賴項)的連接。 如果要將(例如)HTTP請求范圍的bean注入另一個bean,則必須注入AOP代理來代替范圍的bean。 也就是說,您需要注入一個代理對象,該代理對象公開與范圍對象相同的公共接口,但還可以從相關范圍(例如,HTTP請求)中檢索實際的目標對象,並將委托方法調用到實際對象上。
如果正確實現,所有熱切加載的請求范圍的Bean將成為代理。 同樣,不急於加載的請求范圍的Bean要么是代理本身,要么是通過代理加載的。 如果沒有HttpSerlvetRequest
綁定到當前線程,則此操作將失敗。 基本上,對於請求范圍內的bean,在bean依賴關系鏈中的某個位置必須有一個代理。
如果將需求范圍內的組件注入單例中會發生什么?
嘗試一下,您將在應用程序上下文初始化期間得到BeanCreationException
。 錯誤消息清楚地說明了為什么HttpServletRequest
不會發生這種情況:
范圍“請求”對於當前線程無效。 如果您打算從單例中引用它,請考慮為此bean定義作用域代理 。
因此,顯然HttpServletRequest
是作用域代理。 如果要在單例中使用較小范圍的bean,則它們必須是代理。 該文檔詳細介紹了Scoped bean中較小的范圍依賴項作為依賴項 。
[1]:除非你沒有更改默認行為的proxyMode
,這是NO
或嘗試用注入它@Lazy
。 后者可能會導致進入有效的應用程序上下文,但可能導致請求范圍內的bean像單例一樣工作(例如,如果請求范圍內的bean被注入到單例中)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.