I have a web application that is based on Spring. There is defined a bean that holds some class MyClass that is passed also with beans to MyEndpoint that extends AbstractMarshallingPayloadEndpoint.
MyClass has set some boolean parameter in beans to true.
If my application will change this parameter programically to false, does next request will have it also set to false or it will contains a default bean parameter - true ?
It depends on the scope of the bean (which will default to singleton, if you don't specify one).
If it is of singleton scope, there is one instance of that bean in the application context, and each time you ask for that bean, you get that single instance. If you change it in a request with this scope, then the change will be maintained.
If it is of prototype scope, a new instance is given to you (created with the same parameters) each time you ask the application context for it. If you change it in a request with this scope, then the change will be ignored when you get another instance of this object.
These are the two most commonly used (at least with my time in Spring). There are other scopes (request, session, globalsession), but you should read the documentation on them that Spring provides.
If you want this property to change dynamically according to your application business logic and not only to be reset on every new request (otherwise Request scope will do the magic) consider Factory Methods (especially Lookup Method Injection)
Related
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.
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.
Is it possible to define a prototype bean, using XML config or annotation-based config such that I can get an instance of the bean with a custom parameter value? My use case is a message queue handler that makes API calls with different parameter values that are supplied in the inbound message.
In this case it seems I can do one of two things:
Get an instance of my prototype-scope bean and then call setters to customize it to be specific to the inbound message.
Construct a new instance of the bean class using a plain new MyPrototypeBean() and then call setters to customize the instance.
Perhaps a different way of wording my question is: What is the benefit of using a prototype-scope bean vs. using a simple Java constructor?
To get a prototype bean from another bean while passing arguments to constructor you can use <lookup-method> (XML Configuration) or #Lookup (annotation-based configuration).
If you want to get the prototype instance from "unmanaged" code (not from a bean) or you don't want to use the lookup methods, you can achieve the same using org.springframework.beans.factory.BeanFactory.getBean(String beanName, Object...).
Answering your second question, difference between a prototype-scope bean and using a simple Java constructor is that the prototype-scope bean still have access to Spring container's features. This includes, but it's not limited to the following: it can have collaborators provided in XML configuration (<property name="someCollaborator" ref="..."/>) or with annotations (#Resource, #Autowired, ...), t can implement Spring-aware interfaces (like ApplicationContextAware so that the prototype bean itself has access to the container).
I have defined a spring bean extending another bean defined as singleton. Which means this:
<bean id="aChildBean" parent="aParentBean">
<!-- ......->
</bean>
Now, I wonder if I could define the scope "request" in this bean. I know that the child bean inherits the scope of the parent, but I'm not sure that this could logically work. When I tested this, Spring spring generated the exception below:
Error creating bean with name 'aChildBean': 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? ...
So, I wonder if I could do such action. And, if the definition of a scoped bean solve the problem ?
Thanks in advance for your answers..
Quote from documentation:
A child bean definition inherits constructor argument values, property values, and method overrides from the parent, with the option to add new values. Any initialization method, destroy method, and/or static factory method settings that you specify will override the corresponding parent settings.
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
So, your bean IS "request" scoped, but a "request" scope only makes sense in a web environment. See here the documentation of "request" scope.
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).