BeanCreationException for Session scoped bean in #async method - spring

I am stuck into a problem of accessing a session scoped bean in async method.
My Bean definition:
<bean name="ABC" class="java.util.HashMap" scope="session">
<aop:scoped-proxy />
</bean>
My controller class has the annotation '#EnableAsync'.
I am autowiring the class with async method in controller :
#Autowired
AsyncWorker asyncWorker;
When the async method is called, it tries to get the session bean defined above by the following line of code:
Map<String, Object> sessionMap = context.getBean("ABC");
This ends up with the following error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.ABC': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
RequestContextListener is also defined in my web.xml.
All works good when the call is synchronous.
Starting a new thread or using the Async method results in the same error.
Any help on this would be appreciated.

Related

Spring Boot HttpServletRequest Request Scope Bean?

It would seem that HttpServletRequest is a request scope bean, but I have not yet been able to find any documentation on this.
Does anyone know where this is documented or where in the code base it is created?
The HttpServletRequest is normally created and managed by servlet container (e.g. Tomcat) but not Spring. You normally do not need to define it as a spring bean unless you are doing something special. So technically from the spring 's point of view, the HttpServletRequest does not have any scope as it is not a spring bean.
But even if you need to define a HttpServletRequest bean for some reason, by default it will be in the singleton scope. (see the scope table in this).
The relationship between HttpServletRequest and a request scope bean is that Spring will make sure whenever the servlet container process a new HttpServletRequest , it will create a new request scope bean instance in case you need to access it during processing this HttpServletRequest. And this request scope bean will be destroyed after the servlet container finish process that HttpServletRequest. Such behaviour is also mentioned in the above link as :
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext

Spring Boot How can i easy Scope Request bean in Async method?

Spring boot
How can i easy use bean with Request Scope in async method.
When i try execute got exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'bean ! class': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is 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/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
I found a simple solution to this error.
I've initialized the requestScope bean.
which contains #Async method.
Now every request(rest) call with controller receives a new instance of bean.

how does scoped proxy works internally in Spring

consider a case when a prototype-scoped bean is injected into a singleton scoped bean,
when we try to access prototype-scoped bean using the singleton-scoped bean, we are returned with the same bean every time i.e. the bean injected at the time of singleton initialization.
if we want to get different instances everytime we use a scoped proxy.
I did not get the concept how this scoped proxy works behind the stage and how it magically gives us a new instance even if the bean is present inside a singleton.
From the Spring documentation:
3.4.4.5. Scoped beans as dependencies
Being able to define a bean scoped to a HTTP request or Session (or indeed a custom scope of your own devising) is all very well, but one of the main value-adds of the Spring IoC container is that it manages not only the instantiation of your objects (beans), but also the wiring up of collaborators (or dependencies). If you want to inject a (for example) HTTP request scoped bean into another bean, you will need to inject an AOP proxy in place of the scoped bean. That is, you need to inject a proxy object that exposes the same public interface as the scoped object, but that is smart enough to be able to retrieve the real, target object from the relevant scope (for example a HTTP request) and delegate method calls onto the real object.
…
To create such a proxy, you need only to insert a child element into a scoped bean definition (you may also need the CGLIB library on your classpath so that the container can effect class-based proxying; you will also need to be using Appendix A, XML Schema-based configuration). So, just why do you need this element in the definition of beans scoped at the request, session, globalSession and 'insert your custom scope here' level? The reason is best explained by picking apart the following bean definition (please note that the following 'userPreferences' bean definition as it stands is incomplete):
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
<bean id="userManager" class="com.foo.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>

Accessing a SessionScoped bean from another SessionScoped bean more than once in same session creates a new instance

I am experiencing a behavior in my application I do not understand. I have a servlet (Servlet1) that accepts a request, invalidates the current session, creates a new session, and then redirects on the request to a JSF page which references a #Named #SessionScoped bean (Bean1). Both the servlet and the bean #Inject another #SessionScoped bean (SharedBean). The first time I visit my servlet URL everything works correctly. However, the second time I visit the URL the #Named #SessionScoped bean is creating a new instance of sharedbean.
So what I would like to happen is this:
Servlet1 creates a new session
Servlet1 initializes SharedBean
Bean1 access SharedBean
This is happening correctly the first time I access my servlet URL but what is happening on the second invocation is this:
Servlet1 creates a new session
Servlet1 initializes SharedBean
Bean1 creates a new SharedBean
This doesn't seem like the correct behavior to me. I know I am missing something here and I would appreciate someone explaining it to me. Code is below:
Servlet1:
#WebServlet
public class Servlet1 extends HttpServlet
{
#Inject
private SharedBean sbean;
public doGet(HttpServeltRequest request, HttpServletResponse response)
{
HttpSession session = request.getSession();
session.invalidate();
session = request.getSession(true);
this.sbean.initialize();
response.sendRedirect(newURL);
}
}
Bean1:
#Named
#SessionScoped
public class Bean1 implements Serializable
{
#Inject
private SharedBean sbean;
public void actionMethod()
{
this.sbean.execute(); // New instance being created here on 2nd access!
}
}
SharedBean:
#SessionScoped
public class SharedBean implements Serializable
{
public void initialize() { /* do some work */ }
public void exeucte() { /* do some work */ }
}
Because each time the servlet is requested you invalidate the session. So the container creates a new bean or provides another instance. You have to invalidate the session after a certain period of time of inactivity of the user or some other endpoint.
SessionScoped means the bean instance is valid for multiple requests.
But you have to decide what a session means for your application.
In most cases a session is associated to the time a user logs in and logs out. So it is comprised of multiple requests.
So a session is valid for multiple requests and is the same for different servlets.
The session is managed by the servlet container (e.g Tomcat) and an instance of the session object is provided via a ServletContext instance.
You create a new session everytime your servlet is requested. That means the container just creates a ServletContext for this single request and always binds a new bean instance of your SharedBean to that context instance.
UPDATE due to comment.
In this case i would not suggest to let the container manage the bean injection.
Because you never know at what time the bean instance is created and associated with
a SharedBean instance. I think the reason is the issue that you create a new session within you servlet request method. The bean instances of the SharedBean can't be the same in this case, because the container creates an new instance of SharedBean and invalidates the shared bean instance bound to the servlet.
It would be better in this case to create the SharedBean
within the servlet, pass it to the session context as a parameter and use the
SessionContext within the bean to fetch the SharedBean instance.
UPDATE due to COMMENT
The injected beans are managed by the container. Means the container is responsible for creating and destroying the bean. If you create a new instance of the bean the reference (address) or bean instance is decoupled from the servlet container and not managed anymore by the container. So the shared bean reference is not available for your managed bean Bean1
UPDATE due to COMMENT
The answer to the problem is that the instance of the SharedBean which you create within the doGet method of the Servlet method is not communicated to the servlet container and therefor not available for the managed bean Bean1.

Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton

I use JSF with Spring security. I implement it.
My code:
#Named("userDetailsManagerImpl")
#Scope("application")
public class UserDetailBusinessImpl implements UserDetailsService {
#Inject
private MenuBackingBean menu;
}
Everything seem to be good. However I must define MenuBackingBean is application scope. I only want session scope for it. So I change scope to session, but I got an error below:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDetailsManagerImpl': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton
I think this error cause by spring security set application for default scope.
I searched on Google but have no answer for this problem (maybe I have no right keyword searching). Please help me to solve, thank you
More info I used:
JSF 2.0
Spring security 3.1.2
Named and Inject from JSR 330
Scope annotation from springframework package
I suppose that you have this code somewhere:
#Inject
private YourSessionBean yourSessionBean;
// later in some method
this.yourSessionBean.doSomething();
Try to use javax.inject.Provider for all these cases:
#Inject
private Provider<YourSessionBean> yourSessionBeanProvider;
// later in some method
this.yourSessionBeanProvider.get().doSomething();

Resources