Call controller form another bean. No thread-bound request found - java

I'm developing a spring mvc and i want my controller to listen application events
via #controller I send a jms message from a web page
and I'm trying to notify the controller when receiving a message jms, in order to push some data to a web page
First I've tried with the observer pattern, implementing the controller as an ApplicationListener
# Controller ("MyController")
# Scope (value = "session" = proxyMode ScopedProxyMode.TARGET_CLASS)
public class MyController implements Serializable, ApplicationListener <CustomEvent>
Then I've tried to call a controller method from another bean when receiving a jms message
#Resource(name="MyController")
private MyController c;
c.update(String data);
But I'm getting always the same error
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.
Is there a way to call a controller from another bean?
Thanks

The problem is that your controller is session-scoped, and you try to call its method from a context where no HTTP session is available.
So, I assume that your controller combines functionality that depends on HTTP session (thus session scope), and functionality that need to be called outside of a session (such as your update() method).
If so, you can solve this problem by moving functionality that doesn't require HTTP session into separate bean (without session scope).

Related

Spring Boot Request-scoped bean is re-used for multiple requests

Our Spring Boot web application defines a bean that, upon construction, writes a unique ID to the SLF4J MDC (mapped diagnostic context) in order to make it clear in the logs which request caused which log message.
Therefore the bean is request-scoped, i.e. we expect it to only exist as long as exactly one HTTP request is serviced and then it should be destroyed by Spring Boot.
Upon a new request, a new instance should be created, hence there should be a unique REQUEST_ID for every request.
#Component
#Scope(WebApplicationContext.SCOPE_REQUEST)
public class RequestContext {
public RequestContext() {
putInMdc(REQUEST_ID, UUID.randomUUID().toString());
}
...
However, what we observe is lots of unrelated log messages all having the same REQUEST_ID, which can only mean that the constructor of RequestContext is not called between those requests.
All the log messages belong to the same thread ID. I know that Tomcat usually re-uses threads for multiple requests, but shouldn't Spring Boot re-create a request scoped bean anyway as soon as the request is serviced?

Spring Boot: Unable to access the request scope bean in Spring Scheduler

In my Spring Boot application, i've a Scheduler task which executes for every one hour. In the scheduler method trying to access the request-scope bean. Always getting the exception org.springframework.beans.factory.BeanCreationException.
Here is the code sample.
#Data
public class TestVo {
private String message = "Hello";
}
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.TARGET_CLASS)
public TestVo testVo() {
return new TestVo();
}
Accessing the above created bean in scheduler method as below,
#Autowired
private TestVo testVo;
#Scheduled(cron="0 0 * * * *")
public void greetings() {
System.out.println(testVo.getMessage()); // accessing request scope bean
}
getting below exception with above code,
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'scopedTarget.scheduledJobTaskExecutor': 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: In this case, use
RequestContextListener or RequestContextFilter to expose the current
request.
The request scoped beans are bounded to specific requests. Every time a request comes, a new instance will be created and after the request finished it will be destroyed. The request is bounded to a thread and use that thread to process the request (in non reactive environment). Even if it was possible, the scheduler wouldnt know, which request object it should use in this situation. Consider you have 100 active request when the scheduled job starts to run, how it should choose one? Or if there arent any active request (so no instance hold by the context?). You can inject request scope into singleton via proxy because the singleton method call will be handled on the same request thread, but the scheduled job use its own thread pool, which not bounded to any requests.
Maybe now you can see the problem using request scoped bean in the scheduler.
If you want to use the same logic in the scheduler and in request scoped beans, you can for example extract it into a superclass.

Difference between ProxyMode of PROTOTYPE and REQUEST scope

I created a simple Spring Boot project. In the project, I created 2 interfaces which are implemented by 2 service class. One service class is annotated with Prototype scope while another is annotated with Request scope.
Both the service class have proxy mode ScopedProxyMode.INTERFACES
In my Controller class, I am autowiring both the Service class and simply printing out the object. Both are giving me different references every time I make an HTTP request. Why do we need to set the scope as REQUEST if we can achieve the same thing using PROTOTYPE scope?
Definitions
If a bean has PROTOTYPE scope, the Spring IoC container creates a new bean instance every time a request for that bean is made. If a bean has REQUEST scope, every HTTP request will have it's own instance of the bean.
Example
In your example, if you wanted the same reference across the entire lifecycle of your HTTP request, you would want to use REQUEST scope.
I found a nice illustration of the differences between REQUEST and PROTOTYPE scoped beans here.
Documentation

Java EE Request scope and Asynchronous

I am attempting to time an log performance using an interceptor.
#LogPerformance
#Interceptor
public class PerformanceInterceptor {
The times are stored in a request scoped bean. When the the request has finished the times are written to a log file.
When I changed several of the logged methods to be asynchronous, the logging for those operations stopped being output.
#Asynchronous
#LogPerformance
public Future<String> getString() {
I believe the new EJB thread is defining a new request scope. I can log output from the interceptor and see the request scoped object, but there are two different addresses attached to the objects. One address for the http thread and a different address for the EJB thread.
Is there a way to allow the interceptors from the async methods to write to the object in the http request scope? Is there another way to get the data back into the parent scope?
The container will propagate the javax.ejb.EJBContext to the thread that executes the asynchronous method.
You can inject this EJBContext into your interceptor and stash any state (such as your request scoped bean) that you want into it via javax.ejb.EJBContext.getContextData().

how to use a single command object in 2 different page without making it singleton

How do I make transfer of a class object from one page to another in a jsp while doing server process too,
eg let be there a page1.jsp it have a commandObject page1 of a class Page
I then fill some of its value in page1.jsp,
I then want the same object to be transfered to another page say page2.jsp
and on that page I fill the remaining values of page1 object and then persist it to data base.
In the post method of your controller for page 1, add your command object to the model again and return the view name for page 2.
It sounds like you are describing a simple conversation workflow. If your workflow becomes more complex I recommend looking at Spring Webflow.
If you don't wan't to (or can't) use a Singleton bean, how about using the request or session scopes? They are custom-made for this kind of scenario.
3.5.4.2 Request scope
Consider the following bean
definition:
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
The Spring container
creates a new instance of the
LoginAction bean by using the
loginAction bean definition for each
and every HTTP request. That is, the
loginAction bean is scoped at the HTTP
request level. You can change the
internal state of the instance that is
created as much as you want, because
other instances created from the same
loginAction bean definition will not
see these changes in state; they are
particular to an individual request.
When the request completes processing,
the bean that is scoped to the request
is discarded.
3.5.4.3 Session scope
Consider the following bean
definition:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
The Spring container
creates a new instance of the
UserPreferences bean by using the
userPreferences bean definition for
the lifetime of a single HTTP Session.
In other words, the userPreferences
bean is effectively scoped at the HTTP
Session level. As with request-scoped
beans, you can change the internal
state of the instance that is created
as much as you want, knowing that
other HTTP Session instances that are
also using instances created from the
same userPreferences bean definition
do not see these changes in state,
because they are particular to an
individual HTTP Session. When the HTTP
Session is eventually discarded, the
bean that is scoped to that particular
HTTP Session is also discarded.
Source:
Request, session, and global session
scopes

Categories