在Spring 4中运行超出请求范围的代码时,请求范围的Bean始终可用

时间:2020-09-15 14:15:00

标签: java spring spring-boot

在春季4坚持这一点,可能与5相同。

所以,我有什么

  1. Spring Boot 1.5 Web应用程序
  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吗?

1 个答案:

答案 0 :(得分:1)

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

改为使用if (RequestContextHolder.getRequestAttributes() != null)


ObjectProvider的Javadoc说:

ObjectFactory的一种变体,专门为注射点设计,允许程序化的可选性和宽大的非唯一处理。

对于单例bean,ObjectProvider<APIAction>@Autowired(required = false) List<APIAction>的替代方法,其方法可以更好地表示目的。

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

但是,这完全取决于bean的存在性,即关于bean是否已注册(以及注册了多少)。组件扫描会注册任何@Component(或其他)带注释的类,而与bean的 scope 无关。

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

apiAction所引用的对象是一个代理,这一事实除了要点之外,还将根据请求上下文将方法调用应用于不同的实例。

调用APIAction方法时,您会得到IllegalStateException的话:

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

在内部,一个带注释的@RequestScope类具有一个RequestScope类型的Scope,并且Javadoc说:

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

它通过调用RequestContextHolder.currentRequestAttributes()来执行此操作,这会引发上述异常。

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