Reputation: 1200
Stuck on this thing in Spring 4, probably the same will be for 5.
So, what I have:
@RequestScope
@Component
public class APIAction { ... }
private final ObjectProvider<APIAction> apiAction;
apiAction.getIfAvailable()...
null
, exception or something else. Instead I'm receiving some proxy object which can't be tested for null, or any kind of state indicating that bean is really available. If I'll try to invoke any bean method, I'll get exception finally saying accessing to bean outside of thread bounded to web request.So the question is, am I using it wrong? Right now, I'm checking request scope before accessing to bean by invoking this: RequestContextHolder.getRequestAttributes() != null
, which is really ugly, and I need all the time to tell people why they should use it like this.
And bonus question, is it possible actually to instantiate that bean in threads without request bound?
Upvotes: 0
Views: 2860
Reputation: 159086
TL;DR: You can't use ObjectProvider.getIfAvailable()
to check if in request scope.
Use if (RequestContextHolder.getRequestAttributes() != null)
instead.
As the javadoc of ObjectProvider
says:
A variant of
ObjectFactory
designed specifically for injection points, allowing for programmatic optionality and lenient not-unique handling.
For singleton beans, ObjectProvider<APIAction>
is an alternative to @Autowired(required = false) List<APIAction>
with methods that better represent the purpose.
For prototype beans, it allows the on-demand creation of the prototype, including optional constructor arguments.
However, it's all about the existence of the bean, i.e. about whether the bean has been registered (and how many). Any @Component
(or other) annotated class is registered by the component scanning, regardless of the bean scope.
The @RequestScope
bean exists, so the code could be changed to @Autowired private final APIAction apiAction;
, and it would always be non-null.
The fact that the object referred to by apiAction
is a proxy that will apply method calls to different instances depending the the request context is besides the point.
When you call an APIAction
method, you will get an IllegalStateException
saying:
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.
Internally, a @RequestScope
annotated class has a Scope
of type RequestScope
, and the javadoc says:
Relies on a thread-bound
RequestAttributes
instance.
It does this by calling RequestContextHolder.currentRequestAttributes()
, which throws the above exception.
Solution: To check if you are in a request context, call RequestContextHolder.getRequestAttributes()
and check for null
return value.
Upvotes: 3