【发布时间】:2019-09-12 10:48:25
【问题描述】:
如果我尝试将请求范围的 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.
应该如此。
(代码示例见文末)
我知道三种方法可以通过以下测试变绿:
- 更改
UsingBean的范围 - 方法注入
- 范围代理
([1] 与其说是一种解决方案,不如说是一种 hack,并且可能会导致进一步的问题,但它确实将测试变为绿色。:P)
虽然我确实理解这三个选项背后的想法,但我完全不明白为什么它们会起作用。
我的意思是,即使我在 [1] 中将范围更改为“会话”,当我实例化 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正在处理的问题。它将MockServletRequest等绑定到当前正在执行的线程。所以是的,你确实有一个请求。 -
@M.Deinum 谢谢。想从中找出答案吗?
标签: java spring spring-boot kotlin dependency-injection