【问题标题】:Request scoped bean is always available when running code outside of request scope in Spring 4在 Spring 4 中运行超出请求范围的代码时,请求范围 bean 始终可用
【发布时间】:2020-09-15 14:15:00
【问题描述】:

在 Spring 4 中卡住了这个东西,可能在 5 中也是如此。

那么,我有什么:

  1. Spring Boot 1.5 网络应用程序
  2. 请求范围 bean:
  @RequestScope
  @Component
  public class APIAction { ... }
  1. 从与 webrequest 相关或不相关的线程访问此组件的代码:
  private final ObjectProvider<APIAction> apiAction;

  apiAction.getIfAvailable()...
  1. 当它在绑定到 Web 请求的线程中运行时,一切都很好。但是当我从守护线程调用它时,我希望得到null、异常或其他东西。相反,我收到了一些无法测试 null 或任何表明 bean 确实可用的状态的代理对象。如果我尝试调用任何 bean 方法,我最终会得到异常,说访问绑定到 Web 请求的线程之外的 bean。

所以问题是,我用错了吗?现在,我正在通过调用 RequestContextHolder.getRequestAttributes() != null 在访问 bean 之前检查请求范围,这真的很难看,我需要一直告诉人们为什么他们应该这样使用它。

还有一个额外的问题,实际上是否可以在没有请求绑定的线程中实例化该 bean?

【问题讨论】:

  • 我有点困惑,你是说“我在通过调用这个来访问 bean 之前检查请求范围:RequestContextHolder.getRequestAttributes() != null”是在你的守护线程中吗?如果是这样,您是否依赖于请求不会为空的随机机会(当用户发出请求时)并且在同一点您的守护线程将启动?
  • 这不是随机的情况。我正在尝试为计划的作业和休息控制器重用一些代码。所以对于rest api,我有请求范围的bean,它在处理请求期间持有一些缓存。我正在寻找一种方法来简化当前代码而无需一直检查 (RequestContextHolder.getRequestAttributes() != null)

标签: java spring spring-boot


【解决方案1】:

TL;DR:您不能使用ObjectProvider.getIfAvailable() 来检查是否在请求范围内。

请改用if (RequestContextHolder.getRequestAttributes() != null)


正如ObjectProvider 的 javadoc 所说:

ObjectFactory 的一种变体,专为注入点设计,允许编程可选性和宽松的非唯一处理。

对于单例 bean,ObjectProvider&lt;APIAction&gt;@Autowired(required = false) List&lt;APIAction&gt; 的替代方法,其方法更能代表目的。

对于原型bean,它允许按需创建原型,包括可选的构造函数参数。

然而,这一切都是关于 bean 的存在,即关于 bean 是否已注册(以及有多少)。组件扫描注册任何@Component(或其他)注释类,而不管bean 范围

@RequestScope bean 存在,因此可以将代码更改为@Autowired private final APIAction apiAction;,它始终为非空。

apiAction 引用的对象是一个代理,它会根据请求上下文将方法调用应用于不同的实例,这一点并不重要。

当你调用一个APIAction 方法时,你会得到一个IllegalStateException 说:

未找到线程绑定请求:您是指实际 Web 请求之外的请求属性,还是在原始接收线程之外处理请求?如果您实际上是在 Web 请求中操作并且仍然收到此消息,则您的代码可能在 DispatcherServlet 之外运行:在这种情况下,请使用 RequestContextListener 或 RequestContextFilter 来公开当前请求。

在内部,@RequestScope 注释类有一个 Scope 类型为 RequestScope,javadoc 说:

依赖于线程绑定的RequestAttributes 实例。

它通过调用RequestContextHolder.currentRequestAttributes() 来实现这一点,这会引发上述异常。

解决方案:要检查您是否在请求上下文中,请调用RequestContextHolder.getRequestAttributes() 并检查null 返回值。

【讨论】:

  • 好的,似乎在另一个服务中包装检索请求范围的 bean 是隐藏此检查的唯一方法: RequestContextHolder.getRequestAttributes() ! = 空
猜你喜欢
  • 2013-01-21
  • 2011-08-15
  • 1970-01-01
  • 2011-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-11
  • 1970-01-01
相关资源
最近更新 更多