簡體   English   中英

為什么在沒有請求的情況下注入請求范圍的bean?

[英]Why can I inject request-scoped beans in the absence of a request?

如果我嘗試將請求范圍的bean注入單例范圍的bean,那將失敗,因為

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

正如它應該。

(有關代碼示例,請參見本文末尾)

我知道三種通過測試變為綠色的方法:

  1. 更改UsingBean的范圍
  2. 方法注入
  3. 范圍代理

([1]不僅僅是解決方案,而且可能會進一步導致問題,但確實會使測試變成綠色。:P)

盡管我確實了解這三個選項背后的想法,但我仍然不明白它們為什么起作用。

我的意思是,即使我在[1]中將范圍更改為“ session”,在實例化UsingBean時我也沒有會話或請求。

至於[2]和[3],他們避免在啟動時獲取實例,但是當他們實際上確實要獲取實例時,我仍然沒有請求。

但是測試沒有失敗。 為什么?

代碼示例

假設我有一個請求范圍的bean

@Repository
@Scope("request")
class RequestScopedBean : ScopedBean{
    override fun foo(): String {
        return "Hello World"
    }
}

用於單例范圍的

@Service
class UsingBean{
    private val scopedBean:ScopedBean

    @Inject
    constructor(scopedBean: ScopedBean) {
        this.scopedBean = scopedBean
    }

    fun foo():String{
        val foo = scopedBean.foo()
        println(foo)
        return foo
    }
}

我們還為此創建一個小測試:

@RunWith(SpringJUnit4ClassRunner::class)
@SpringBootTest
@WebAppConfiguration
class RequestScopedBeansIT{

    @Inject
    private lateinit var bean : UsingBean

    @Test
    fun canInject(){
        assertThat(bean.foo()).isEqualTo("Hello World")
    }
}

1)更改 UsingBean 的范圍

@Service
@Scope("session")
class UsingBean{
    private val scopedBean:ScopedBean

    @Inject
    constructor(scopedBean: ScopedBean) {
        this.scopedBean = scopedBean
    }

    fun foo():String{
        val foo = scopedBean.foo()
        println(foo)
        return foo
    }
}

2)方法注入

@Service
class UsingBean{
    private val scopedBean:ScopedBean
        get() = injectBean()

    fun foo():String{
        val foo = scopedBean.foo()
        println(foo)
        return foo
    }

    @Lookup
    fun injectBean():ScopedBean{
        TODO("will be replaced by spring")
    }
}

3)范圍代理

@Repository
@Scope("request",proxyMode = ScopedProxyMode.TARGET_CLASS)
class RequestScopedBean : ScopedBean{
    override fun foo(): String {
        return "Hello World"
    }
}

要么

@Repository
@RequestScope
class RequestScopedBean : ScopedBean{
    override fun foo(): String {
        return "Hello World"
    }
}

盡管您可能認為自己沒有最新的請求和會話,但實際上確實有一個。

@WebAppConfiguration是觸發它的原因。 它將激活ServletTestExecutionListener ,它將注冊一個線程綁定的ServletTestExecutionListener請求和響應。

這就解釋了為什么在存在線程綁定請求的情況下測試成功的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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