繁体   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