java - 为什么我可以在没有请求的情况下注入请求范围的 bean?
问题描述
如果我尝试将请求范围的 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
就是触发它的原因。它将激活ServletTestExecutionListener
将注册一个线程绑定的模拟请求和响应。
这解释了为什么测试成功,因为存在线程绑定请求。
推荐阅读
- javascript - 动态导入组件以生成静态站点
- r - Tidymodels svm_rbf kernlab:达到最大迭代次数
- angular - “从不”类型上不存在属性“标题”
- python - 将出现在字符串中的元素放入列表中
- node.js - “退避操作已在进行中” - Firebase 管理员 SDK Electron
- react-redux - 如何使用 react-redux 更改功能组件中的路由器历史记录
- ruby-on-rails - 在 rspec 中为测试数据创建可重用类
- python - 如何使用 matplotlib 调整 PySimpleGUI 画布的大小
- sorting - 我们可以通过尾递归优化随机快速排序吗?
- html - 使用类名获取元素