How to create a request-scoped bean manually? - java

I have a request-scoped bean which are used in app. Now I need to implement some predefined configuration beans. I tried both ways:
as a InitializingBean implementation
as a spring's ApplicationListener<ApplicationReadyEvent> listener
but the problem is that code within this config beans uses erquest-scoped bean and everytime I get a:
Caused by: 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?
is there any way of simulating request?

Related

string being in previous state even after triggering a new request java

I am working on a spring boot api where I have used a query string and doing some replace operations on it on every get request but even after I trigger a new request the string is in the same state as that of previous GET call and the query gets messed up.
Here's my code:
private static String GET_SETS = "Select * from table #check#";
Now I have 1 method in the same repository which gets called on a get request:
public PagedList getSets(Map params) {
if (!StringCheck.isEmpty(flattenMap.get("entity_name"))) {
GET_SETS = GET_CODE_SETS.replace("#check#", " WHERE e.#entity_name# = ?");
values.add((String)flattenMap.get("entity_name"));
} else {
GET_SETS = GET_SETS.replace("#check# #status_check#", "");
}
}
Now whenever a GET request is triggered,some changes are done to GET_SETS string according to map values,and again in the next requests the same changes are there.
How to solve this? I want the query string to be whats defined at the start on every request. Thanks
Your problem is most likely caused by using the default scope, which is singleton, when creating your Spring components.
Spring provides the following scopes for creating beans
(source):
singleton (default): Scopes a single bean definition to a single object instance for each Spring IoC container
prototype: Scopes a single bean definition to any number of object instances.
request: 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.
session: Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring
ApplicationContext.
application: Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring
ApplicationContext.
websocket: Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring
ApplicationContext.
If we don't specify any scope explicitly, the default singleton scope is used. This means that the service/component is shared between multiple injections, hence it is reused for multiple GET requests.
In order to get rid of this behavior, we might use something like request scope, although in this case we have to take care of thread-safety as well.
Other solution is to not use member variables and try to use local variables for things such as GET_SETS.

Spring boot instantiate multiple components

I have a callable type class. It is a annotated with #component. I would like to create multiple instances of the callable class. To do so, I am using the application context. The problem is it simply does not work.
Refer Bean scope you want to use:
https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch04s04.html#:~:text=2%20The%20prototype%20scope,method%20call%20on%20the%20container).
singleton - once for each IoC container, your application context
prototype- multiple beans for multiple object instance
request - in case of web aware app context, each bean to a particular HTTP request, and new instance for another
session- for each HTTP session.
global session - as what name says.
depending on your use select scope as well explained by #BeUndead.

How can I use ApplicationContext session scoped classes from a different thread

Using #Async annotation I want to call a method in a different thread that has access to Session and Request scoped classes.
However when the ApplicationContext tries to get the bean the following exception is generated:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.sessionInfoClass': Scope 'session' is not active for the current thread;
I had tried extending ApplicationContextAware class to hold the main thread context.
Also I had tried the suggested solution from this question How to enable request scope in async task executor
Source coude is in Github
https://github.com/saavedrah/spring-threadSample
I have created a pull request for your repo that solves the issue.
Basically, I extended this solution also for Runnable case.
To verify it, run the ThreadSampleApplication class then hit http://localhost:8080/testAsync

Inject HttpServletRequest into Controller

As I know per default are controllers in Spring MVC singletons. HttpServletRequest passed offen to the controller handler method. And its ok, while HttpServletRequest is request-scoped, but I see often HttpServletRequest gets #Autowired into the controller field, like this:
#Controller("CMSProductComponentController")
#RequestMapping(CMSProductComponentController.CONTROLLER_PATH)
public class CMSProductComponentController {
#Autowired
private HttpServletRequest request;
}
Could be this a problem? And more general question: What happens if inject a reqeust-scoped component into a singleton?
No, for HttpServletRequest it will not be a problem and it shouldn't for other request scoped beans. Basically, Spring will generate a proxy HttpServletRequest that wraps some kind of ObjectFactory (RequestObjectFactory for HttpServletRequest) (YMMV) that knows how to retrieve the actual instance. When you use any of the methods of this proxy, they will delegate to that instance.
What's more, this is done lazily, so it won't fail at initialization. It will however fail if you try to use the bean when there is no request available (or if you haven't registered the RequestScope).
The following is in response to the comments and to clarify in general.
Regarding the proxy-mode attribute of #Scope or the XML equivalent, the default is ScopedProxyMode.NO. However, as the javadoc states
This proxy-mode is not typically useful when used with a non-singleton
scoped instance, which should favor the use of the INTERFACES or
TARGET_CLASS proxy-modes instead if it is to be used as a dependency.
With request scoped beans, this proxy-mode value will not work. You'll need to use INTERFACES OR TARGET_CLASS depending on the configuration you want.
With scope set to request (use the constant WebApplicationContext.SCOPE_REQUEST), Spring will use RequestScope which
Relies on a thread-bound RequestAttributes instance, which can be
exported through RequestContextListener, RequestContextFilter or
DispatcherServlet.
Let's take this simple example
#Component
#Scope(proxyMode = ScopedProxyMode.INTERFACES, value = WebApplicationContext.SCOPE_REQUEST)
public class RequestScopedBean {
public void method() {}
}
...
#Autowired
private RequestScopedBean bean;
Spring will generate two bean definitions: one for your injected bean, a singleton, and one for the request scoped bean to be generated on each request.
From those bean definitions, Spring will initialize the singleton as a proxy with the types of your target class. In this example, that is RequestScopedBean. The proxy will contain the state it needs to produce or return the actual bean when it is needed, ie. when a method is called on the proxy. For example, when
bean.method();
is called.
This state is basically a reference to the underlying BeanFactory and the name of the request-scoped bean definition. It will use these two to generate a new bean and then call method() on that instance.
The documentation states
The Spring IoC container manages not only the instantiation of your
objects (beans), but also the wiring up of collaborators (or
dependencies). If you want to inject (for example) an HTTP request
scoped bean into another bean, you must 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 can
also retrieve the real, target object from the relevant scope (for
example, an HTTP request) and delegate method calls onto the real
object.
All eagerly loaded request scoped beans, if implemented correctly, will be proxies. Similarly, request scoped beans that aren't eagerly loaded will either be proxies themselves or be loaded through a proxy. This will fail if there is no HttpSerlvetRequest bound to the current thread. Basically, a proxy is necessary somewhere in the bean dependency chain for request scoped beans.
What happens if inject a reqeust-scoped component into a singleton?
Try it and you'll get a BeanCreationException¹ during application context initialization. The error message clearly explains why this doesn't happen with HttpServletRequest:
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;
So obviously HttpServletRequest is a scoped proxy. If you want to use beans of smaller scopes in singletons they have to be proxies. The documentation elaborates about smaller scoped dependencies in Scoped beans as dependencies.
[1]: unless you didn't change the default behaviour for proxyMode, which is NO or try to inject it with #Lazy. The latter might result into a valid application context but might lead to request scoped beans acting like singletons (e.g. if a request scoped bean is injected into a singleton).

Spring #Autowired and WebApplicationContext in Tomcat

#Autowired works only once.
What to do to make it wire the bean every time the Servlet is recreated?
My web-app (Tomcat6 container) consists of 2 Servlets. Every servlet has private fields.
Their setters are marked with #Autowired
In the init method I use
WebApplicationContextUtils
...
autowireBean(this);
It autowires the properties marked with #Autowired once - during the initialization of the Servlet.
Any other session will see these fields values, they will not be rewired after the previous session is destroyed.
What to do to make them rewire them each time a Servlet constructor is called?
a) Put the autowiring into the constructor?
Or better 2) get a web app context and extract a bean from there?
There seems to be some misunderstanding about how the container works. Servlets are essentially singletons, you don't get a new servlet everytime someone calls the server. Storing state in private fields on a servlet is pretty much an error.
What is the scope and life-cycle of the stateful part of your request processing? If it's just the life of the request then you can take whatever on your servlet is stateful and move it into another class. Then you can define a prototype bean for that class and use getBean at the start of the request to get a new one. If you want to start getting fancy you could write a filter that puts a new bean into a ThreadLocal at the start of each request.
If your state needs to span multiple requests, you need to start keeping state or a key that points to the state storage on the web session, or look into using a conversation framework.
Try using scope as prototype for that bean #Scope("prototype")
You may try to use #Scope("session")

Categories

Resources