簡體   English   中英

將HttpServletRequest注入控制器

[英]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將不起作用 您需要根據所需的配置使用INTERFACESTARGET_CLASS

scope設置為request (使用常量WebApplicationContext.SCOPE_REQUEST ),Spring將使用RequestScope

依賴於線程綁定的RequestAttributes實例,該實例可以通過RequestContextListenerRequestContextFilterDispatcherServlet導出。

讓我們舉一個簡單的例子

@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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM